OpenJSX / jsx-to-html

Render JSX-IR to HTML string
MIT License
33 stars 3 forks source link

Top level element should be a tag or function which returns a tag #3

Open inspiraller opened 7 years ago

inspiraller commented 7 years ago

Hi I have installed this plugin but having problems.

$ npm install jsx-to-html

myreactfile.jsx

import React, { Component } from 'react';
import { render } from 'jsx-to-html';

class App extends Component {
    getComp(){
        var content = render(<div className="hello">hello</div>);
        console.log('content = ', content);
        return ('<div>hello</div>');
    }
    render() {
        return (
            <div className="all">
            {this.getComp()}
        </div>
        )
    }
}

ReactDOM.render(
    <App/>,
    document.getElementById('app')
);

I am getting error: Uncaught Error: Top level element should be a tag or function which returns a tag

I have tried adding the plugin via .babelrc but that gives me an error too so I'm not entirely sure the plugin has loaded:

.babelrc

{
  "presets" : ["es2015", "react"],
    "plugins": [
        ["jsx-to-html/babel-plugin",
        { 
            "blacklist": ["react"]
        }]
    ]
}
NekR commented 7 years ago

@inspiraller This plugin was written for Babel 5 and wasn't really intended to be used with React. Why do you even use it?

inspiraller commented 7 years ago

Jsx is react isn't it? In anycase i want to render my jsx components into a html string so i can escape the tags to becomr pre/code examples before rendering thrm into a documentation page.

The only way i can think to do that currently is render them first into a fragment, then read the innerhtml to escape the tags before rendering it again. I don't like that method because its not as performant.

SleeplessByte commented 7 years ago

No need for babel or anything else:

import { render } from 'react-dom'

function getReactNodeHtml(node) {
  const detached = document.createElement('div')
  ReactDom.render(node, detached)
  return detached.innerHtml
}

Then use:

const html = getReactNodeHtml((<div className="hello">hello</div>))
console.log(html)

//<div data-reactroot="" class="hello">hello</div>

You probably want to get rid of the data-reactroot attribute:

import { render } from 'react-dom'
const REACT_ROOT_PATTERN = new RegExp(/data-reactroot(?:="")?\s?/)

function getReactNodeHtml(node) {
  const detached = document.createElement('div')
  render(node, detached)
  return detached.innerHtml.replace(REACT_ROOT_PATTERN, '')
}

// <div class="hello">hello</div>

Here is the Typescript without TSX/JSX equivalent

import { render } from 'react-dom'
const REACT_ROOT_PATTERN = new RegExp(/data-reactroot(?:="")?\s?/)

function getReactNodeHtml(node: JSX.Element) {
  const detached = document.createElement('div')
  render(node, detached)
  return detached.innerHTML.replace(REACT_ROOT_PATTERN, '')
}

const html = getReactNodeHtml(createElement('div', { className: 'hello' }, 'hello'))
console.log(html)

// <div class="hello">hello</div>
inspiraller commented 7 years ago

Thanks. Yes, that is what I am already doing, but as I said I would rather not have to render it first to improve performance. Regards. Thanks for the code example.