从字符串创建React类的实例

时间:2015-05-11 16:04:02

标签: class dynamic reactjs instance

我有一个字符串,其中包含Class的名称(这来自json文件)。这个字符串告诉我的Template Class哪个布局/模板用于数据(也在json中)。问题是我的布局没有显示。

Home.jsx:

//a template or layout.
var Home = React.createClass({
  render () {
    return (
    <div>Home layout</div>
    )
  }
});

Template.jsx:

var Template = React.createClass({
  render: function() {
    var Tag = this.props.template; //this is the name of the class eg. 'Home'
    return (
        <Tag />
    );
  }
});

我没有收到任何错误,但我也没有看到布局/家庭班级。我检查了props.template,这会记录正确的信息。此外,我可以在DOM中看到home元素。但它看起来像这样:

<div id='template-holder>
    <home></home>
</div>

如果我将以下行更改为:

var Tag = Home;
//this works but it's not dynamic!

任何想法,我如何解决这个问题?我确定它既可以是简单的解决方案,也可能是我做一些愚蠢的事情。帮助将不胜感激。如果已经问过这个问题我抱歉(我无法找到)。

谢谢, 伊万

6 个答案:

答案 0 :(得分:14)

这不起作用:

repo_b

然而,这将:

git fetch origin
git checkout master
git merge origin/master

因此,您只需找到一种在字符串 var Home = React.createClass({ ... }); var Component = "Home"; React.render(<Component />, ...); 组件类 var Home = React.createClass({ ... }); var Component = Home; React.render(<Component />, ...); 之间进行映射的方法。一个简单的对象将作为基本注册表使用,如果您需要更多功能,可以从那里构建。

"Home"

答案 1 :(得分:7)

如果您可以将所有组件放在一个模块中,那么无需手动将类映射到字典即可实现:

   import * as widgets from 'widgets';
   var Type = widgets[this.props.template];
   ...
   <Type />

通配符import语句已经是一个字典,代码就像上一个答案中的注册表一样。

实际上,我认为你可以使用一个额外的映射来处理多个模块:

import * as widgets from 'widgets';
import * as widgets2 from 'widgets2';

const registry = Object.assign({}, widgets, widgets2);
const widget = registry[this.props.template];

我会完全这样做。事实上,我认为我是。

答案 2 :(得分:2)

我遇到了同样的问题,并且自己找到了解决方案。我不知道是否是最好的实践和#34;但它确实有效,我现在正在使用它。

你可以简单地利用&#34; evil&#34; eval函数,用于动态创建react组件的实例。类似的东西:

function createComponent(componentName, props, children){
  var component = React.createElement(eval(componentName), props, children);
  return component;
}

然后,只需将其调用到您想要的位置:

var homeComponent = createComponent('Home', [props], [...children]);

如果它符合您的需求,也许您可​​以考虑这样的事情。

希望它有所帮助。

答案 3 :(得分:1)

使用JSX时,您可以呈现HTML标记(字符串)或React组件(类)。

当你执行var Tag = Home时,它的工作原理是因为JSX编译器将其转换为:

var Template = React.createElement(Tag, {});

变量Tag在同一范围内,并且是React类。

    var Tag = Home = React.createClass({
                       render () {
                         return (
                         <div>Home layout</div>
                         )
                       }
                     });

当你这样做时

var Tag = this.props.template; // example: Tag = "aClassName"
你正在做什么

var Template = React.createElement("aClassName", null);

但&#34; aClassName&#34;不是有效的HTML标记。

here

答案 4 :(得分:1)

这是一种从字符串内容开始工作的方式,而无需像其他人建议的那样将组件作为静态链接的代码嵌入到程序包中。

import React from 'react';
import { Button } from 'semantic-ui-react';
import createReactClass from 'create-react-class';

export default class Demo extends React.Component {
    render() {
        const s = "return { render() { return rce('div', null, rce(components['Button'], {content: this.props.propA}), rce(components['Button'], {content: 'hardcoded content'})); } }"
        const createComponentSpec = new Function("rce", "components", s);
        const componentSpec = createComponentSpec(React.createElement, { "Button": Button });
        const component = React.createElement(createReactClass(componentSpec), { propA: "content from property" }, null);

        return (
            <div>
                {component}
            </div>
        )
    }
}

React类规范位于字符串s中。请注意以下几点:

rce代表React.createElement,并在调用createComponentSpec时作为第一个参数给出。

components是额外组件类型的字典,在调用createComponentSpec时作为第二个参数给出。这样做是为了为您提供具有冲突名称的组件。

例如,字符串Button可以解析为标准HTML按钮或语义UI中的按钮。

您可以按照https://babeljs.io中的说明使用https://reactjs.org/docs/react-without-jsx.html来轻松为s生成内容。本质上,该字符串不能包含JSX内容,并且必须是纯JavaScript。 BabelJS就是通过将JSX转换为JavaScript来完成的。

您需要做的就是将React.createElement替换为rce,并通过components字典解析外部组件(如果不使用外部组件,则可以跳过字典内容)。

这里等同于上面的代码。具有两个语义UI <div>的同一Button

JSX render()代码:

function render() {
  return (
    <div>
      <Button content={this.props.propA}/>
      <Button content='hardcoded content'/>
    </div>
  );
}

BabelJS将其翻译为:

function render() {
  return React.createElement("div", null, React.createElement(Button, {
    content: this.props.propA
  }), React.createElement(Button, {
    content: "hardcoded content"
  }));
}

并且您如上所述进行更换:

render() { return rce('div', null, rce(components['Button'], {content: this.props.propA}), rce(components['Button'], {content: 'hardcoded content'})); }

调用createComponentSpec函数将为React类创建一个规范。

然后使用createReactClass将其转换为实际的React类。

然后与React.createElement一起变得生动起来。

您需要做的就是从主要组件render函数中返回它。

答案 5 :(得分:0)

我想知道如何根据从数据库加载的JSON规范动态创建React类,所以我做了一些实验并想出来了。我的基本想法是我想通过GUI定义一个React应用程序,而不是在文本编辑器中输入代码。

这与React 16.3.2兼容。注意React.createClass已移至其自己的模块中。

以下是基本部分的精简版本:

import React from 'react'
import ReactDOMServer from 'react-dom/server'
import createReactClass from 'create-react-class'

const spec = {
  // getDefaultProps
  // getInitialState
  // propTypes: { ... }
  render () {
    return React.createElement('div', null, 'Some text to render')
  }
}
const component = createReactClass(spec)
const factory = React.createFactory(component)
const instance = factory({ /* props */ })
const str = ReactDOMServer.renderToStaticMarkup(instance)
console.log(str)

您可以在此处看到更完整的示例:

https://github.com/brennancheung/02-dynamic-react/blob/master/src/commands/tests/createClass.test.js