我有一个字符串,其中包含类的名称(这来自一个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 />
);
}
});
我没有得到任何错误,但我也没有看到布局/ Home Class。我检查了props.template,这会记录正确的信息。此外,我可以在DOM中看到home元素。但它看起来像这样:
<div id='template-holder>
<home></home>
</div>
如果我将以下行更改为:
var Tag = Home;
//this works but it's not dynamic!
任何想法,我如何解决这个问题?我确定它要么是简单的修复,要么是我做了一些愚蠢的事情。帮助将不胜感激。如果已经有人问过这个道歉(我找不到)。
谢谢,Ewan
这不起作用:
var Home = React.createClass({ ... });
var Component = "Home";
React.render(<Component />, ...);
但是,这将:
var Home = React.createClass({ ... });
var Component = Home;
React.render(<Component />, ...);
所以你只需要找到一种方法来在字符串"Home"
和组件类Home
之间进行映射。一个简单的对象将作为基本注册表使用,如果需要更多功能,可以从那里构建。
var components = {
"Home": Home,
"Other": OtherComponent
};
var Component = components[this.props.template];
如果您可以将所有组件放在一个模块中,那么无需手动将类映射到字典即可实现:
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];
我完全会这样做。事实上我认为我是。
我遇到了同样的问题,并自己找到了解决方案。我不知道是否是“最好的实践”,但它有效,我现在在我的解决方案中使用它。
您可以简单地使用“邪恶”eval函数来动态创建反应组件的实例。就像是:
function createComponent(componentName, props, children){
var component = React.createElement(eval(componentName), props, children);
return component;
}
然后,只需将其调用到您想要的位置:
var homeComponent = createComponent('Home', [props], [...children]);
如果它符合您的需求,也许您可以考虑这样的事情。
希望能帮助到你。
正如其他人所建议的那样,以下是字符串内容的工作方式,而无需将组件作为静态链接代码嵌入到包中。
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的按钮。
您可以使用s
中描述的https://babeljs.io轻松生成https://reactjs.org/docs/react-without-jsx.html的内容。本质上,字符串不能包含JSX的东西,并且必须是纯JavaScript。这就是BabelJS通过将JSX转换为JavaScript所做的事情。
你需要做的就是用React.createElement
替换rce
,并通过components
字典解析外部组件(如果你不使用外部组件,你可以跳过字典的东西)。
这与上面的代码相同。相同的<div>
有两个语义UI Button
s。
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
func返回它。
使用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);
但“aClassName”不是有效的HTML标记。
看看here
我想知道如何从数据库加载的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