使用 React.lazy 动态地 select 一个组件

Using React.lazy to dynamically select a component

我正在开发一个显示任务列表的应用程序。当用户单击任务时,它应该显示一个表单,以便用户可以更新该任务的状态。然而,有不同类型的任务,需要根据任务类型呈现正确的形式。每个任务类型都有一个任务定义,其中包含一个标识该任务所需表单的字段。当有人点击一个任务时,任务对象,包括任务 formComponent 被传递给 formWrapper 组件。每个表单组件都在一个 JSX 文件中,它们都导出为 TaskForm。

我需要 select 基于任务定义的组件。我认为我可以通过执行以下操作 react.Lazy 来完成此操作:

在formWrapper的componentDidMount():

    // Store the path to the required JSX file in the state.
    this.setState( {formFile: '../Processes/'+this.state.task.formComponent} );

然后在formWrapper的render()中:

    TaskForm = React.lazy(() => import(this.state.formFile));
    return (
        <Suspense fallback={<div>Loading...</div>}>
             <TaskForm task={this.props.task} />
        </Suspense>

当我启动 node.js 时,它会抛出警告“关键依赖项:依赖项的请求是一个表达式”并且无法加载表单。

我离正确的轨道还很近吗?我不能静态定义表单。其中有几个,它们可能会发生变化。

代码必须是静态可分析的,因为 Webpack(我相信这是您用来捆绑应用程序的工具)需要知道需要哪些文件,以便将它们包含在捆绑包中。采用 this.state.formFile.

这样的表达式是不够聪明的

我相信当您说您不能静态定义表单时是不正确的,或者至少不能容忍这样做。文件是可枚举的,都可以导入到这个文件中。

我想您想根据某些条件动态导入组件。我为此创建了一个小函数:

const getComponent = (path) => {
  const Component = React.lazy(() => import(`${path}`));
  return Component;
};

// Usage

render() {
 const Component = getComponent(path);
 return <Component />;
}

这是工作沙盒:https://codesandbox.io/s/intelligent-snowflake-c0l6y?file=/src/App.js:306-344

这是实时部署的应用程序:https://csb-c0l6y.netlify.app/

您可以通过网络请求确认,当我们Load Component B 请求新文件时。

Note: 我还没有对这个模式进行实战测试。我认为它可能对性能有一些影响,但应该很容易修复。

在与@backtick 交流后,我最终的解决方案是将所有表单 JSX 文件放在一个文件夹中,其中包含一个 index.js 文件,该文件导出文件夹中的每个表单(没有其他代码在文件中,仅导出):

export { Form1 } from './Form1';
export { Form2 } from './Form2';

然后,在需要加载其中一个表单的文档中,我从数据库中读取表单名称,并使用它在我的 render() 函数中延迟加载表单:

        const MyForm = React.lazy(() => import('../forms')
            .then(forms => (
                { default: forms[this.state.formFile] }
            ))
        );

.then函数默认导出选中的表单,MyForm中只保存一个组件。如果 this.state.formFile = Form1,则加载 Form1。

在我的表单的 return() 中,我将 MyForm 作为一个组件包含在内:

                    <Suspense fallback={<div>Loading...</div>}>
                        <MyForm task={this.props.task} formVariables={this.state.formVariables}/>
                    </Suspense>