render React component from a string

2019-08-01 02:48发布

问题:

I have some React code in the string, for example:

const component = `
function App() {
  return (
    <div>
    test
    </div>
  );
}
`;

And I want to be able to render that component from within browser, something like:

import React, { Component } from 'react';
import { render } from 'react-dom';
import * as babel from 'babel-standalone';


const babelCode = babel.transform(component, { presets: ['react', 'es2015'] }).code;

render(eval(babelCode), document.getElementById('WorkFlow'));

This particular example doesn't work but it shows what I'm looking for, any help appreciated!

Thanks!

回答1:

Babel produces the code with "use strict" and eval() doesn't work with it well. First, we should remove that line manually.

const code = babelCode.replace('"use strict";', "").trim();

Ideally, after this following lines should work.

eval(code);
render(<App/>, document.getElementById('WorkFlow'));

Note that you don't need to put eval() inside render. It doesn't return your App function or anything. Instead, it will add App to context and we can use it after eval() statement.

But usually, React app has a compile step with webpack or similar tool and will complain about undefined App.

As a workaround, we can wrap our component with a Function which returns our component itself. Now we can call this function to get our component. But the context of wrapping function doesn't have React variable. So we have to pass it manually as a parameter. If you are going to use any other variable from the current context, you will have to pass those as well.

const code = babelCode.replace('"use strict";', "").trim();
const func = new Function("React", `return ${code}`);
const App = func(React)
render(<App/>, document.getElementById('WorkFlow'));

Hope this helps!



回答2:

React will allow you to render either a Component or an Element. You can think of an Element as a raw HTML code in JSX, while a Component is a prototype, which inherits from React.Component. In your code you are trying to render a result of evaluating the babel transpiled code, which will fail (I'm not sure what it is, but it's probably undefined or null). If you want to make it work, first evaluate the code and then invoke the function to pass the Element code to the render function:

eval(babelCode);  // now the App function has been defined and you can use it in the code
render(App(), document.getElementById('WorkFlow'));
       // ^^ here the App function is being invoked

Old answer (I thought you were trying to pass the component as a file not and not as a variable to transpiler):

babel will never transpile strings, so this is not going to work out for you. You can however consider using a raw JS code instead of JSX as your string content. More about it you can read here: https://facebook.github.io/react/docs/react-without-jsx.html