我试图根据组件的类型动态呈现组件。
例如:
var type = "Example";
var ComponentName = type + "Component";
return <ComponentName />;
// Returns <examplecomponent /> instead of <ExampleComponent />
我尝试了这里提出的React/JSX动态组件名称的解决方案
这在编译时给了我一个错误(使用browserify for gulp)。当我使用数组语法时,它期望XML。
我可以通过为每个组件创建一个方法来解决这个问题:
newExampleComponent() {
return <ExampleComponent />;
}
newComponent(type) {
return this["new" + type + "Component"]();
}
但这意味着我创建的每个组件都有一个新方法。这个问题一定有更优雅的解决办法。
我很愿意接受建议。
编辑:
正如gmfvpereira最近指出的,有一个官方文档条目:
https://reactjs.org/docs/jsx-in-depth.html#choosing-the-type-at-runtime
对于包装器组件,一个简单的解决方案就是使用React。直接createElement(使用ES6)。
import RaisedButton from 'mui/RaisedButton'
import FlatButton from 'mui/FlatButton'
import IconButton from 'mui/IconButton'
class Button extends React.Component {
render() {
const { type, ...props } = this.props
let button = null
switch (type) {
case 'flat': button = FlatButton
break
case 'icon': button = IconButton
break
default: button = RaisedButton
break
}
return (
React.createElement(button, { ...props, disableTouchRipple: true, disableFocusRipple: true })
)
}
}
<MyComponent />编译为React。createElement(MyComponent,{}),它需要一个字符串(HTML标签)或一个函数(ReactClass)作为第一个参数。
您可以将组件类存储在一个名称以大写字母开头的变量中。参见HTML标签vs React组件。
var MyComponent = Components[type + "Component"];
return <MyComponent />;
编译,
var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});
应该有一个容器将组件名称映射到所有应该动态使用的组件。组件类应该注册在容器中,因为在模块化环境中,没有单独的地方可以访问它们。如果不显式地指定组件类,就不能通过它们的名称来标识它们,因为在生产环境中函数名被简化了。
组件图
它可以是plain object:
class Foo extends React.Component { ... }
...
const componentsMap = { Foo, Bar };
...
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
或Map实例:
const componentsMap = new Map([[Foo, Foo], [Bar, Bar]]);
...
const DynamicComponent = componentsMap.get(componentName);
普通对象更适合,因为它受益于属性简写。
桶模块
具有命名exports的桶模块可以充当这样的map:
// Foo.js
export class Foo extends React.Component { ... }
// dynamic-components.js
export * from './Foo';
export * from './Bar';
// some module that uses dynamic component
import * as componentsMap from './dynamic-components';
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
如果每个模块代码风格有一个类,效果会很好。
装饰
装饰器可以用于类组件的语法糖,这仍然需要显式地指定类名并将它们注册到map中:
const componentsMap = {};
function dynamic(Component) {
if (!Component.displayName)
throw new Error('no name');
componentsMap[Component.displayName] = Component;
return Component;
}
...
@dynamic
class Foo extends React.Component {
static displayName = 'Foo'
...
}
装饰器可以作为功能组件的高阶组件使用:
const Bar = props => ...;
Bar.displayName = 'Bar';
export default dynamic(Bar);
使用非标准的displayName而不是random属性也有利于调试。