前言
React开发过程中,大部分都是单页面应用,不做代码分片的话,所有的js文件都打成一个庞大的bundlejs文件,随着项目内容的不断增多,首屏空白时间就会变得越来越长。
因此可以对代码进行分片,打包时生成多个js文件,每次页面只请求所需要的js文件,用户体验大大提升。
法一:Loadable实现(不推荐)
在React16.6之前懒加载流行使用Loadable包。
- 安装依赖
npm i react-loadable -S
- 路由配置
import React from 'react';
import Loadable from 'react-loadable';
const Loading = () => <div>loading</div>; // 定义一个组件,在组件加载前展示,组件加载完成之后消失
const Index = Loadable({
loader: () => import('../views/Index/Index'),
loading: Loading
});
const PageOne = Loadable({
loader: () => import('../views/PageOne/PageOne'),
loading: Loading
});
const PageTwo = Loadable({
loader: () => import('../views/PageTwo/PageTwo'),
loading: Loading
});
export default [
{
path: '/',
component: Index,
exact: true,
title: '首页',
},
{
path: '/PageOne',
component: PageOne,
exact: true,
title: '登录',
},
{
path: '/PageTwo',
component: PageTwo,
exact: true,
title: '登录',
},
];
- App.js
import React, { Component } from 'react';
import {
Route,
Switch,
Redirect,
BrowserRouter as Router
} from 'react-router-dom';
// 这里的是路由配置文件
import routes from './router/index';
export default class App extends Component {
render() {
return (
<Router>
<Switch>
{
routes.length > 0 && routes.map((route) => { //遍历路由数组
const {
path,
component:C, // 这样写,是为了以下写法中,用C来代替标签如<Home />,因为不能<component />
exact,
} = route;
return (
<Route
exact={exact}
key={path}
path={path}
render={(props) => {
// 实际上这里会处理很多的业务逻辑,如权限和登录(无token自动跳转到登录页),相当于vue的导航守卫
// console.log(props);
return (<C />);
}}
/>
);
})
}
{/* 默认进入/时自动匹配到/Home */}
<Redirect
exact
from="/"
to={'/'}
/>
{/* 默认无效路径时自动匹配到首页 */}
<Redirect to="/" />
</Switch>
</Router>
);
}
}
如果react是高版本,会出现这样的警告,所以不推荐使用此方法
法二: 使用react的lazy,Suspense方法实现分片打包
- 路由配置
import { lazy } from 'react';
const PageOne = lazy(() => import('../views/PageOne/PageOne'));
const PageTwo = lazy(() => import('../views/PageTwo/PageTwo'));
const Index = lazy(() => import('../views/Index/Index'));
export default [
{
path: '/',
component: Index,
exact: true,
title: '首页',
},
{
path: '/PageOne',
component: PageOne,
exact: true,
title: '登录',
},
{
path: '/PageTwo',
component: PageTwo,
exact: true,
title: '登录',
},
];
- App.js,引入并使用Suspense包裹要懒加载的组件(Route)
import React, { Suspense, Component } from 'react';
import {
Route,
Switch,
Redirect,
BrowserRouter as Router
} from 'react-router-dom';
// 这里的是路由配置文件
import routes from './router/index';
export default class App extends Component {
render() {
return (
<Router>
<Suspense fallback={<div>loading</div>}>
<Switch>
{
routes.length > 0 && routes.map((route) => { //遍历路由数组
const {
path,
component:C, // 这样写,是为了以下写法中,用C来代替标签如<Home />,因为不能<component />
exact,
} = route;
return (
<Route
exact={exact}
key={path}
path={path}
render={(props) => {
// 实际上这里会处理很多的业务逻辑,如权限和登录(无token自动跳转到登录页),相当于vue的导航守卫
// console.log(props);
return (<C />);
}}
/>
);
})
}
{/* 默认进入/时自动匹配到/Home */}
<Redirect
exact
from="/"
to={'/'}
/>
{/* 默认无效路径时自动匹配到首页 */}
<Redirect to="/" />
</Switch>
</Suspense>
</Router>
);
}
}
对redux进行分割
对页面进行分割后,可以进一步的切割页面所需要的数据,我们使用store的replaceReducer方法 在store.js中,添加一个维护当前reducer的对象,和一个更新reduer的方法。
let asyncReducers = {};
export const getNewReducer = (newModuleInfo) => {
asyncReducers[newModuleInfo.name] = newModuleInfo.reducer;
store.replaceReducer(combineReducer({
...asyncReducers,
}))
}
在reducerC文件中,需要调用该方法
import { getNewReducer } from './store.js';
const state = { value: '' };
const reducer = (state = state, action) => {
switch(action.type) {
case 'setValue':
return { ...state, value: action.value };
default:
return state;
}
}
export default getNewReducer({ name: 'reducerC', reducer });
文章参考
https://juejin.im/post/6844903953721737224
https://www.jianshu.com/p/164be62145a7
https://segmentfault.com/a/1190000020247862?utm_source=tag-newest
https://blog.csdn.net/xutongbao/article/details/84822315