React 通过react-loadable实现异步组件
在一般的react项目中在性能优化方面除了减少各种静态资源的体积外,还有一个效果显著的方式,异步加载组件,包括页面级组件(在路由中配置的),以及其他的体积较大的第三方组件(bizcharts,bScroll,...),本文会详细说明使用react-loadable来实现三种异步组件:
- 页面级组件(router.js引用的组件),普通的react组件
- bizcharts 组合的react组件
- bScroll 等非典型react组件(第三方类库)
准备
项目中安装 react-loadable ,babel插件安装 syntax-dynamic-import. react-loadable是通过webpack的异步import实现的
如果要实现非页面的组件加载,首先要在webpack配置中将相应的代码块分离出来,splitchunk!!! (例如,bizcharts 等代码库,需要在splitchunk中给个单独配置)
react-loadable的基本使用和概念,其中import中的webpackChunkName是异步文件的文件名。
现在我们来讲list页面实现异步组件,其中在Loadable方法的参数配置中,
import Loadable from 'react-loadable';
// 首次加载
const Loading = ({ isLoading, error }) => {
if (isLoading) {
return 加载中...;
} else if (error) {
return 页面加载出现问题, 请刷新后重试;
}
return null;
};
const AsyncList = Loadable({
loader: () => import(/* webpackChunkName: 'page_list' */'@pages/list'),
loading: Loading
});
- loading 是一个接受状态对象的函数,isLoading和error属性,通过这两个属性来返回相应的过渡组件
- loader 是一个返回import()调用的函数
- render 如果loader中只是个普通的react组件这个办法不需要用到,但是如果加载js或者组件时一个组件的集合就需要用到,其中loaded是加载的文件的export结果,props 是Loadable函数返回组件接收的参数。
const A = Loadable({
loader,
render: (loaded, props) => {
const CurComponent = 条件?loaded.default : loaded.other
return ;
},
loading,
});
此时props就是{in:tue}
页面级组件(router.js引用的组件),普通的react组件
未使用react-loadable之前的页面,如下:
// 首次加载
import Index from '@pages/index';
import List from '@pages/list';
const Routes = () => (
);
现在我们来讲list页面实现异步组件,其中在Loadable方法的参数配置中,可以根据项目需要修改loading中的过渡效果
import Loadable from 'react-loadable';
// 首次加载
import Index from '@pages/index';
const Loading = ({ isLoading, error }) => {
if (isLoading) {
return 加载中...;
} else if (error) {
return 页面加载出现问题, 请刷新后重试;
}
return null;
};
const AsyncList = Loadable({
loader: () => import(/* webpackChunkName: 'page_list' */'@pages/list'),
loading: Loading
});
const Routes = () => (
如果加载的js是个组件的集合,例如components.jsx 文件
export A =()=>{A};
export B =()=>{B};
export C =()=>{C};
此时要加载A页面,需要在render函数中的loaded参数获得A属性即A组件
const AsyncA = Loadable({
loader: () => import(/* webpackChunkName: 'page_list' */'@pages/list'),
render: (loaded, props) => {
const CurComponent = loaded.A; // A组件
return ;
},
loading: Loading
});
普通的react组件的加载类似普通的页面的加载
bizcharts 的异步实现,bizcharts的export类似上面的组件的组合,一般项目中用到的图表每个都会写到单独处理的文件里,chartA.js chartB.js,...,每个chart文件大概这样子:
import React from 'react';
import { Chart, Geom, Axis, Tooltip, Label, Guide, } from 'bizcharts';
class Index extends React.Component {
render()
return (
);
}
}
export default Index;
先写一个通用的异步加载chart的函数getBizcharts,loading和上文提到的一样,函数的参数ReactComponent 就是原来的chartA,chartB组件 render 函数中的loader就是bizchart对象,通过getBizcharts函数就可以在chartA的组件的props.bizchart中获取和原来一样的bizcharts组件。
import Loadable from 'react-loadable';
export const getBizcharts = (ReactComponent) => Loadable({
loader: () => import(/* webpackChunkName: "bizcharts" */'bizcharts'),
render: (loaded, props) => ,
loading: Loading
});
这是图表组件的样子:
import React from 'react';
import { getBizcharts } from '@components/getAsyncComponent';
// import { Chart, Geom, Axis, Tooltip, Label, Guide, } from 'bizcharts';
class Index extends React.Component {
render()
const {
Chart, Geom, Axis, Tooltip, Label, Guide,
} = this.props.bizchart;
return (
);
}
}
export default getBizcharts(Index);
在render中通过props.bizchart获取bizchart组件,导出时调用getBizcharts方法
bScroll 等非react组件
如果该类组件的export 是一个单独的构造,就是在render的时候出入 loaded.default
如果是一个集合,可以直接出入,在使用的组件中获取