React asynchronous loading component implementation analysis

React asynchronous loading component implementation analysis

For react development, I believe that react+webpack is already a popular package. As for other parcels or rollups or other construction frameworks, I have not used them carefully and are not familiar with it. I heard that there have been tens of thousands of parcels on github in a short time. Stars, very bad sample paper, but this is not the focus of our article, ha ha. This article focuses on the asynchronous loading of modules. I won t talk about other things here, only on-demand loading optimization. When using webpack to build, we will put public resources into the vendor file in order to make our business files thin, but our business may have a large number of sub-businesses, and some businesses may never be available to certain users. Used, in this case, if we load all the business code all at once, isn t it too wasteful and extravagant. Fortunately, webpack itself provides the require.ensure() function, but this optimization method is not in us. Within the scope of this discussion, this time we will introduce the relatively tall react asynchronous loading component in my mind. Even if you don t like it, it s a great thing to learn. Let s take a look at the following code. If you don t use asynchronous module loading, page1 and page2 will be merged into one business file. If I never enter the/buy route, isn t this a waste of loading? Then page2 is better to be made as an asynchronous component. Well, what should I do?

<Route path="/" component={App}>
		<IndexRoute component={page1}/>
		<Route path="/buy" component={page2}/>
	</Route>
 

Okay, isn't it just an asynchronous component? Isn't that simple? It's just like the following:

let page2 = ()=>{
    let page2Comp = import('lazyComp');
    return {
        <div>
            <page2Comp/>
        </div>
    }
}
 

Oops, this IQ is also high. I thought I was cheating, and realized an asynchronous component in just a few lines, naive! It's a pity that an error was reported. I don't know why? Let's take a look at what is returned by import(). What people return is a promise object. At least it must be processed first. It's like if you invite someone to your house for a banquet, you must at least arrange a seat first, take a chair to occupy a hole, and wait until they come to remember to move the stool, no one is happy, turn around and leave. . How can I take a pit? In fact, the truth is very simple, everyone is familiar with it, please look at the following little chestnut.

class MyComp extends React.Component{
    constructor(){
        return {
            isLoaded:false
        }
    }
    render(){
        let { isLoaded, data } = this.state;
        if(!isLoaded){
            return null;
        }
        return <Wrapper data={data}/>
    }
    componentDidMount(){
        http.getData({}).then((results)=>{
            this.setState({
                data:results.data,
                isLoaded:true
            })
        })
    }
}
 

Everyone is familiar with this code. Before the data is returned, no specific rendering is performed. Rendering is not started until the data is returned. The only difference here is that the asynchronous component is the component itself. What should I do before the component is obtained? It's simple, it's OK to use an empty element to occupy the one place. Next, let's take a look at an asynchronous component implementation provided by the webpack official website :

class LazilyLoad extends React.Component {

	constructor() {
		super(...arguments);
		this.state = {
			isLoaded: false,
		};
	}

	componentDidMount() {
		this._isMounted = true;
		this.load();
	}

	componentDidUpdate(previous) {
		if (this.props.modules === previous.modules) return null;
		this.load();
	}

	componentWillUnmount() {
		this._isMounted = false;
	}

	load() {
		this.setState({
			isLoaded: false,
		});

		const { modules } = this.props;
		const keys = Object.keys(modules);

		Promise.all(keys.map((key) => modules[key]()))
			.then((values) => (keys.reduce((agg, key, index) => {
				agg[key] = values[index];
				return agg;
			}, {})))
			.then((result) => {
				if (!this._isMounted) return null;
				this.setState({ modules: result, isLoaded: true });
			});
	}

	render() {
		if (!this.state.isLoaded) return <div className="toast toast-show">
			<Loading/>
		</div>;
		console.log("modules:",this.state.modules);
		return React.Children.only(this.props.children(this.state.modules));
	}
}
 

Do you think it is closely related to the chestnut that loads data asynchronously above? Next, let's take a look at this code in detail. I won't say much about it in other places. Perhaps some students may not understand return React.Children.only(this.props.children(this.state.modules));this code in the render function . This rendering method is called callback rendering. To make an analysis for everyone, let s take a look at the sample code for calling the above components:

const LazilyLoadFactory = (Component, modules) => {
	console.log("LazilyLoadFactory");
	return (props) => (
		<LazilyLoad modules={modules}>
			{(mods) => <Component {...mods} {...props}/>}
		</LazilyLoad>
	);
};
 

If you still don't understand, first return React.Children.only(this.props.children(this.state.modules));disassemble a few elements in the above code:

  • this.props.children: Everyone should know what this means. It refers to the child element of the calling component. In the above example, doesn't it refer to (mods) => <Component {...mods} {...props}/>this function?
  • this.state.modules: This is where the modules variable passed in props in the LazilyLoad component is processed into state variables
  • React.Children.only: Needless to say, I must be familiar with it

After a little disassembly, is it clear? Looking back at our stateless component LazilyLoadFactory, the LazilyLoad component is rendered. The method of using callback rendering actually uses the parameter modules as the props input parameter to the parameter component Component. Rendering, it is very obvious, the parameter component Component is the bench of this asynchronous component, let's take a look at the specific code of the component passed in as a parameter:

class WrapLazyComp extends React.Component{
	render(){
		const Comp = this.props.Comp;
		return <div>
			<Comp/>
		</div>;
	}
}
 

Okay, then the next step is our total caller

LazilyLoadFactory(WrapLazyComp,{
	Comp: () => import(' ')
});
 

So far, our asynchronous components are complete. The main thing is to use import() to implement asynchronous loading of modules. Some students may be a little vague about callback rendering, and those who are unfamiliar may need to understand a little. I personally prefer this method to load asynchronous modules. Of course, there are methods such as require.ensure. The specific optimization method depends on personal preference and the specific situation of the project, and cannot be generalized. Okay, thank you, if there are any mistakes, please advise me a lot.