应该有一个容器,将组件名称映射到所有应该动态使用的组件中。组件类应该在容器中注册,因为在模块化环境中,否则没有单一的地方可以访问它们。组件类不能仅通过其名称进行识别,而需要明确指定它们,因为生产中的函数name
被缩小了。
组件映射
它可以是普通对象:
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);
普通对象更适合,因为它受益于属性速记。
桶模块
使用命名导出的桶模块可以充当这样的映射:
export class Foo extends React.Component { ... }
export * from './Foo';
export * from './Bar';
import * as componentsMap from './dynamic-components';
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
使用每个模块一个类的代码风格,这很有效。
装饰器
可以将装饰器用于类组件以获得语法糖,但仍需要显式指定类名并在映射中注册:
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
而不是随机属性,还可以更好地进行调试。
{...this.props}
很有用,它可以把父组件的props透明地传递给子组件。例如:return <MyComponent {...this.props} />
。 - Dr.Strangelove