动态加载反应组分

mad*_*ode 19 reactjs webpack

我需要动态加载react组件.

我得到要从用户加载为字符串的组件的名称.我正在使用webpack.

如何动态加载组件而不是静态导入语句.似乎Require.Ensure不评估表达式.我想要实现的是这样的.

require.ensure([ "./widgets/" + componentName ] ,(require) => {
    let Component = require("./widgets/" + componentName);   
});
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用.

fac*_*com 20

基本上它归结为预先创建你将需要的所有块.那么你只需要一种动态引用它们的方法.这是我所依据的解决方案:

http://henleyedition.com/implicit-code-splitting-with-react-router-and-webpack

这就是我做的事情,因为我不使用React Router(旁注:我发现它不是一个很好的匹配redux或动画):

//loader:
{
  test: (folder)\/.*\.js,
  include: path.resolve(__dirname, 'src')
  loader: ['lazy?bundle', 'babel']
}

//dynamic usage within React component:
const My_COMPONENTS = {
   ComponentA: require('./folder/ComponentA'),
   ComponentB: require('./folder/ComponentB'),
}

class ParentComponent extends React.Component {
    componentDidMount() {
        My_COMPONENTS[this.props.name](component => this.setState({component}));
    } 
    render() {
       return <this.state.component />;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,结果是您动态呈现一个组件,但是从一组静态预定的可能性 - 同时,只发送给客户端而不是访问者实际感兴趣的块.

此外,这是我有一个很好的组件:

import React from 'react';
import Modal from './widgets/Modal';

export default class AjaxModal extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      Content: null
    };
  }

  componentDidMount() {
    if(this.props.show) {
      this.loadContent();
    }
  }

  componentWillReceiveProps({show}) {
    if(show && !this.state.Content) {
      this.loadContent(1200); //dont interfere with animation
    }
  }

  loadContent(ms=0) {
    setTimeout(() => {
      this.props.requestLazyBundle(({default: Content}) => {
        this.setState({Content});
      });
    }, ms);
  }

  render() {
    let {Content} = this.state;

    return (
      <Modal title={this.props.title} {...this.props} loading={!Content}>
        {Content ? <Content /> : null}
      </Modal>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

传递async require bundler函数this.props.requestLazybundle,如下所示:

render() {

  let requestLazyBundle = require('bundle?lazy&name=AnotherComponent!../content/AnotherComponent');

  return (
    <AjaxModal title='Component Name' {...props} requestLazyBundle={requestLazyBundle} />
  );
}
Run Code Online (Sandbox Code Playgroud)


Sam*_*igh 6

请查看我为完整源代码提供的这个要点页面 https://gist.github.com/SamanShafigh/a0fbc2483e75dc4d6f82ca534a6174d4

因此,假设您有4个组件,分别为D1,D2,D3.您需要的是创建依赖注入和依赖容器机制.这是一个非常简单的实现

想象一下,你有一个这样的配置文件来定义你的组件

export default [
  {
    name:'D1',
    path:'D1'
  },
  {
    name:'D2',
    path:'D2'
  },
  {
    name:'D3',
    path:'D3'
}];
Run Code Online (Sandbox Code Playgroud)

然后你可以有一个像这样的组件容器

import componentsConfig from 'ComponentsConfig';

let components = {};

for (var i = 0; i < componentsConfig.length; i++) {
  let componentConfig = componentsConfig[i];
  // Check if component is not already loaded then load it
  if (components[componentConfig.name] === undefined) {
    components[componentConfig.name] = require(`${componentConfig.path}`).default;
  }
}

export default components;
Run Code Online (Sandbox Code Playgroud)

最后,在您要加载组件的位置,您可以使用组件容器动态加载组件,或者换句话说,您可以注入组件

import React, { Component } from 'react';
import ComponentContainer from './ComponentContainer';

class App extends Component {
  render() {
    let components = ['D1', 'D2', 'D3'];

    return (
      <div>
        <h2>Dynamic Components Loading</h2>
        {components.map((componentId) => {
          let Component = ComponentContainer[componentId];
          return <Component>{componentId}</Component>;
        })}
      </div>
    );
  }
}

export default App;
Run Code Online (Sandbox Code Playgroud)

  • @LionelDcosta我已经提供了代码https://gist.github.com/SamanShafigh/a0fbc2483e75dc4d6f82ca534a6174d4但是请做更多研究来发现这种方法的缺点,我不确定它是否适合大型项目 (2认同)