首页 > 网站 > WEB开发 > 正文

react按需加载

2024-04-27 15:12:12
字体:
来源:转载
供稿:网友

react-router webpack 按需加载,与路由权限控制

说明

当网站规模越来越大,通过webpack 打包后的 react 项目也会越来越大,这会导致首页渲染时间变长,影响用户体验,webpack 提供了一种按需加载的方式,需要结合 react-router 使用,他会将代码拆分成多个小包,需要哪个部分就加载响应的包。

webpack 配置

首先需要对 config 文件修改一下,如下

output: { path: path.join(__dirname, 'dev'), // 输出路径 filename: '/js/bundle.js', // 输出文件名 publicPath: path.join(__dirname, 'dev'), // 必填项 chunkFilename : '/js/routes/[name].chunk.js?[chunkhash:10]', // 按需加载输出的文件名 },

路由配置页(app/js/routes.js

react 按需加载,关键是让路由动态加载组件,react-router 提供了一个属性 getComponent ,它与 component 属性一样,但是是异步的,当路由匹配时才会调用这个方法,常用于代码分割; 相关内容查看 API文档

webpack 为我们提供了一个按需加载函数 require.ensure(dependencies, callback, chunkName)

dependencies : 依赖的模块数组callback : 回调函数,该函数调用时会传入一个 require 参数chunkName : 模块名,用于构建时生成文件名

更多了解,查看官方文档

一般写法
/* app/js/routes.js 路由配置文件 */ import React from 'react'; import { Route, IndexRoute} from 'react-router'; // 引入容器组件 import App from './containers/App'; export default ( <Route path="/" component={App}> <IndexRoute getComponent={(location, cb) => { require.ensure([], require => { cb(null, require('./containers/Login.js').default) },'login'); }} /> <Route path="home" getComponent={(location, cb) => { require.ensure([], require => { cb(null, require('./containers/Home.js').default) },'home'); }} /> <Route path="login" getComponent={(location, cb) => { require.ensure([], require => { cb(null, require('./containers/Login.js').default) },'login'); }} /> </Route> );

注意:cb(null, require('./containers/Login.js').default) 因为我用 es6 的 export default 导出的组件,所以 require 之后要加上 default,如果使用 module.export 导出组件 则不需要加 default

拆分写法

以上写法在 路由层级或者数量较多的时候会比较臃肿,所以还需要对路由进行拆分

路由拆分,需要对目录结构做一下改变,在js 文件夹下添加 routes 路由配置文件夹

|---js | |---actions | | | |---components | | | |---containers | | | |---reducers | | | |---store | | | |---routes | | |---login.js // 主路由的下一级路由 | | |---login // login 路由的下一级路由目录 | |---constants.js // 静态常量 | |---index.js // 项目入口文件 | |---routes.js // 路由配置主文件 |

routes.js 路由配置的主文件

const routes = { path : '/', // 将匹配的路由,对应标签中的 path 属性 indexRoute: { // 设置默认显示页面,对应标签中的 IndexRoute 组件 getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('./containers/Login').default); }, 'Login'); } }, // childRoutes:[] // 子 route 的一个数组,与在 JSX route 配置中的 children 一样。 getChildRoutes(partialNextState, cb) { // 与 childRoutes 一样,但是是异步的,并且可以接收 partialNextState(location 信息) require.ensure([], (require) => { cb(null, [ require('./routes/login'), require('./routes/home'), require('./routes/error') ]) }) }, getComponent(nextState, cb) { // 定义对应的组件,对应标签中的 component 属性,但是是异步的,路由匹配时才会调用这个方法 require.ensure([], (require) => { // require.ensure : webpack 提供的按需加载方法 cb(null, require('./containers/App').default); }, 'App'); } } export default routes;

js/routes/home.js 路由分支

module.exports = { path: 'home', getChildRoutes(partialNextState, cb) { require.ensure([], (require) => { cb(null, [ require('./home/page'), require('./home/student'), require('./home/admin') ]) }) }, getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('../containers/Home').default) }, 'Home') } }

路由权限控制

基本思路 : 每当指定路由要发生改变,就使用一个中间服务,介于上一级路由和将要到达路由之间启动,来判断我们是否有进入这个路由的权限,React 中的 <Route /> 提供了一个 onEnter方法,表示正要进入这个路由,在这里判断进入权限,可以修改要进入的页面

<Route path="home" getComponent={(location, cb) => { require.ensure([], require => { cb(null, require('./containers/Home.js').default) },'home'); }} onEnter={request}/>function request(nextState, replace, next){ let auth = nextState.location.query.auth; if(auth === 'home'){ next(); } else if (auth === 'other') { replace('/other'); next(); } else { replace('/'); next(); }}

注:nextState : 表示跳转后的location 信息;replace 用于 更改下一个进入的页面地址,但是不会跳转;next : 用于跳转页面,没有其他操作则显示当前路由对应页面

如果使用路由拆分,如下

module.exports = { path: 'home', getChildRoutes(partialNextState, cb) { require.ensure([], (require) => { cb(null, [ require('./home/page'), require('./home/student'), require('./home/admin') ]) }) }, getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('../containers/Home').default) }, 'Home') }, onEnter: (nextState, replace, next) => { console.log(nextState.location.state); let isAuth = nextState.location.state.isAuth; if (isAuth === 'student' || isAuth === 'teacher' || isAuth === 'admin') { next(); } else { replace('/error'); next(); } } }
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表