Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
616 views
in Technique[技术] by (71.8m points)

reactjs - Dynamic loading of react components

I need to load a react component dynamically.

I get name of the component to load as a string from user. I'm using webpack.

How do I load the component dynamically instead of having a static import statement. It seems Require.Ensure doesn't evaluate expressions . What I want to achieve is something like this.

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

But this doesn't seem to work.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Basically it boils down to pre-creating all the chunks you will ever need. Then you just need a way to dynamically refer to them. Here's the solution I based mine on:

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

and here's what I do since I don't use React Router (side note: i dont find it to be a good match for redux or animations):

//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 />;
    }
}

So the result is you are dynamically rendering a component, but from a static pre-determined set of possibilities--all while, only sending no more to the client than the chunks the visitor is actually interested in.

ALSO, here's a component I have that does this well:

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>
    );
  }
}

pass pass an async require bundler function as this.props.requestLazybundle, like this:

render() {

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

  return (
    <AjaxModal title='Component Name' {...props} requestLazyBundle={requestLazyBundle} />
  );
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...