react大型项目的按需加载和代码拆分。

2019-03-31  本文已影响0人  TouchMe丶

REACT中的按需加载

按需加载,顾名思义,需要什么我们才加载什么资源。传统的单页应用(SPA)在首屏就会加载整个应用所有页面的结构,样式与逻辑。所以首屏的加载速度会大大降低,从而影响用户体验。有什么方法能让首屏加载变快呢?其中最最重要的就是spa的按需加载了,也可以叫相应页面的异步加载。

方法1:使用react-loadable模块辅助进行按需加载

本项目用的create-react-app来构建
这个方法是我最常用的。其中用到了一个react-router官方提供的第三方库,react-loadable。这个库主要是用来帮助我们完成按需加载的。
react-loadable
具体用法,参照官方给出的example。
安装之后,我们首先在需要按需加载的组件的同文件夹下创建一个loadable.js文件,如下

import React from "react";
import Loadable from 'react-loadable';

const LoadableComponent = Loadable({
  loader: () => import('./'), //这里相当于再加同文件夹下的index.js
  loading(){//这里是加载进行时,页面上要显示的ui
    return <div>正在加载</div>
  }
});
export default ()=> <LoadableComponent/>

然后,在入口文件中,我们写上关于路由的改变

//Detail变成一个异步组件了
import Detail from "./pages/detail/loadable.js";
//以及
<Route exact path="/detail/:id" component={Detail}></Route>

注意,由于Detail是loadable.js导出的模块,经过上面的包装,就会让loadable.js内的模块获取到props,但同时,props没法传入到真正的Detail,所以在Detail组件中,我们无法获取到react-router提供的history,进而没法进行一些关于路由的操作。
所以在Detail组件文件中,我们进行以下操作:

import { withRouter } from "react-router-dom";
//加载一个react-router-dom提供的withRouter对Detail进行包裹
export default withRouter(Detail);

方法一会把Detail的相关逻辑拆分出去,然后再首屏加载的时候对该部分进行忽略,等到我们进入detail页面,再进行加载。达到了代码拆分的目的。

方法2:import()方法:

import()函数是es6模块化标准之后才出现的新的特性。以前的import方法只能在文件中加载另一个文件导出的模块。现在,应用import()方法,我们可以在括号里面写相应加载函数,可以起到运行时加载的作用,就实现了了相应的按需加载功能。配合webpack相应的配置,同时实现代码拆分。
首先,我们在工具文件夹utils当中,写一个asyncload高阶组件,放在asyncload文件夹下的asyncComponent.js中.
让我们来写一个名为AsynComponent的高阶组件。它接收一个函数,函数返回平常的组件。经过包装后返回。

import React,{ PureComponent } from "react";

export default function AsyncComponent(importComponent){
  class AsyncComponent extends PureComponent{
    constructor(props) {
      super(props);
      this.state = {
        component:null
      };
    }
    async componentDidMount(){
      const { default:component } = await importComponent();
      this.setState({
        component:component
      });
    }
    render(){
      const C = this.state.component;
      return C ? <C {...this.props}/> : null
    }
  }
  return AsyncComponent;
}

然后再入口文件app.js中:

// import()异步加载
import AsyncComponent from "./utils/asyncload/asyncComponent";
const BasicImport = AsyncComponent(() => import("./pages/imports"));
//import()方法加载了imports里面的index.js,并返回一个promise

<Route exact path="/impt" component={BasicImport}></Route>

这样也能把impt对应的impt代码分隔开来。构建的时候就能看到,多了相应的js文件。并且不会再首屏加载。

上一篇下一篇

猜你喜欢

热点阅读