详解react-router4 异步加载路由两种方法


Posted in Javascript onSeptember 12, 2017

方法一:我们要借助bundle-loader来实现按需加载。

首先,新建一个bundle.js文件:

import React, { Component } from 'react'

export default class Bundle extends React.Component {

  state = {
    // short for "module" but that's a keyword in js, so "mod"
    mod: null
  }

  componentWillMount() {
    this.load(this.props)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.load !== this.props.load) {
      this.load(nextProps)
    }
  }

  load(props) {
    this.setState({
      mod: null
    })
    props.load((mod) => {
      this.setState({
        // handle both es imports and cjs
        mod: mod.default ? mod.default : mod
      })
    })
  }

  render() {
    if (!this.state.mod)
      return false
    return this.props.children(this.state.mod)
  }
}

然后,在入口处使用按需加载:

// ...

// bundle模型用来异步加载组件
import Bundle from './bundle.js';

// 引入单个页面(包括嵌套的子页面)
// 同步引入
import Index from './app/index.js';
// 异步引入
import ListContainer from 'bundle-loader?lazy&name=app-[name]!./app/list.js';

const List = () => (
  <Bundle load={ListContainer}>
    {(List) => <List />}
  </Bundle>
)

// ...

  <HashRouter>
    <Router basename="/">
      <div>
        <Route exact path="/" component={Index} />
        <Route path="/list" component={List} />
      </div>
    </Router>
  </HashRouter>

// ...


webpack.config.js文件配置
output: {
  path: path.resolve(__dirname, './output'),
  filename: '[name].[chunkhash:8].bundle.js',
  chunkFilename: '[name]-[id].[chunkhash:8].bundle.js',
},

方法二:用原生的

Webpack 配置

首先在 webpack.config.js 的 output 内加上 chunkFilename

output: {
  path: path.join(__dirname, '/../dist/assets'),
  filename: 'app.js',
  publicPath: defaultSettings.publicPath,
  // 添加 chunkFilename
  chunkFilename: '[name].[chunkhash:5].chunk.js',
},

name 是在代码里为创建的 chunk 指定的名字,如果代码中没指定则 webpack 默认分配 id 作为 name。

chunkhash 是文件的 hash 码,这里只使用前五位。

在路由页面

这里写的是旧的没按需要加载的路由写法

ReactDOM.render(
 (
  <Router history={browserHistory}>
   {/* 主页 */}
   <Route path="/" component={App}>
    {/* 默认 */}
    <IndexRoute component={HomePage} />

    {/* baidu */}
    <Route path="/baidu" component={BaiduPage}>
     <Route path="result" component={BaiduResultPage} />
     <Route path="frequency" component={BaiduFrequencyPage} />
    </Route>

    {/* 404 */}
    <Route path='/404' component={NotFoundPage} />
    
    {/* 其他重定向到 404 */}
    <Redirect from='*' to='/404' />
   </Route>
  </Router>
 ), document.getElementById('app')
);

我们需要让路由动态加载组件,需要将 component 换成 getComponent

ReactDOM.render(
 (
  <Router history={browserHistory}>
   {/* 主页 */}
   <Route path="/" component={App}>
    {/* 默认 */}
    <IndexRoute component={HomePage} />

    {/* baidu */}
    <Route path="/baidu"




getComponent(nextState, cb) 





{ require.ensure([], (require) => { cb(null, require('components/layer/HomePage')) }, 'HomePage')}>
     <Route path="result"   getComponent... />
     <Route path="frequency" getComponent... />
    </Route>
    {/* 404 */}
    <Route path='/404' getComponent... />
    {/* 其他重定向到 404 */}
    <Redirect path='*' onEnter: (_, replaceState) => replaceState(null, "/404") />
   </Route>
  </Router>
 ), document.getElementById('app')
);

getComponent

对应于以前的 component 属性,但是这个方法是异步的,也就是当路由匹配时,才会调用这个方法。

这里面有个 require.ensure 方法

require.ensure(dependencies, callback, chunkName)

这是 webpack 提供的方法,这也是按需加载的核心方法。第一个参数是依赖,第二个是回调函数,第三个就是上面提到的 chunkName,用来指定这个 chunk file 的 name。

如果需要返回多个子组件,则使用 getComponents 方法,将多个组件作为一个对象的属性通过 cb 返回出去即可。这个在官方示例也有,但是我们这里并不需要,而且根组件是不能返回多个子组件的,所以使用 getComponent。 

当改写之后,我们需要把这个重定向的路由单独拆出来,也就是 * 这个路由,我们上面已经为他创建了一个 redirect 目录。这里使用到 onEnter 方法,然后在这个方法里改变路由状态,调到另外的路由,实现 redirect :

/redirect/index.js

module.exports = {
 path: '*',
 onEnter: (_, replaceState) => replaceState(null, "/404")
}

The root route must render a single element

跟着官方示例和上面码出来之后,可能页面并没有渲染出来,而是报 The root route must render a single element 这个异常,这是因为 module.exports 和 ES6 里的 export default 有区别。

如果你是使用 es6 的写法,也就是你的组件都是通过 export default 导出的,那么在 getComponent 方法里面需要加入.default。

getComponent(nextState, cb) {
  require.ensure([], (require) => {
   // 在后面加 .default
   cb(null, require('components/layer/ReportPage')).default
  }, 'ReportPage')
}

如果你是使用 CommonJS 的写法,也就是通过 module.exports 导出的,那就无须加 .default 了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
EditPlus注册码生成器(js代码实现)
Mar 25 Javascript
在Linux系统中搭建Node.js开发环境的简单步骤讲解
Jan 26 Javascript
Bootstrap每天必学之附加导航(Affix)插件
Apr 25 Javascript
bootstrap的3级菜单样式,支持母版页保留打开状态实现方法
Nov 10 Javascript
Javascript中字符串replace方法的第二个参数探究
Dec 05 Javascript
基于JS实现弹出一个隐藏的div窗口body页面变成灰色并且不可被编辑
Dec 14 Javascript
使用微信内嵌H5网页解决JS倒计时失效问题
Jan 13 Javascript
javascript checkbox/radio onchange不能兼容ie8处理办法
Jun 13 Javascript
js解决软键盘遮挡输入框的问题分享
Dec 19 Javascript
基于Vue实现可以拖拽的树形表格实例详解
Oct 18 Javascript
解决vue admin element noCache设置无效的问题
Nov 12 Javascript
使用Canvas绘制一个游戏人物属性图
Mar 25 Javascript
JS+canvas绘制的动态机械表动画效果
Sep 12 #Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
Sep 12 #Javascript
Angular 4.0学习教程之架构详解
Sep 12 #Javascript
jQuery+vue.js实现的九宫格拼图游戏完整实例【附源码下载】
Sep 12 #jQuery
详解vue axios中文文档
Sep 12 #Javascript
javascript算法之二叉搜索树的示例代码
Sep 12 #Javascript
vue-resouce设置请求头的三种方法
Sep 12 #Javascript
You might like
php生成扇形比例图实例
2013/11/06 PHP
主流PHP框架的优缺点对比分析
2014/12/25 PHP
PHP把MSSQL数据导入到MYSQL的方法
2014/12/27 PHP
PHP实现算式验证码和汉字验证码实例
2015/03/09 PHP
PHP微信开发用Cache 解决数据缓存
2016/07/11 PHP
php实现统计二进制中1的个数算法示例
2018/01/23 PHP
EXTJS内使用ACTIVEX控件引起崩溃问题的解决方法
2010/03/31 Javascript
麻雀虽小五脏俱全 Dojo自定义控件应用
2010/09/04 Javascript
jQuery的ready方法详解
2014/11/27 Javascript
JavaScript中string转换成number介绍
2014/12/31 Javascript
JavaScript常用的弹出广告及背投广告实现方法
2015/02/06 Javascript
JavaScript中window.open用法实例详解
2015/04/15 Javascript
jquery validate表单验证插件
2016/09/06 Javascript
JS作用域闭包、预解释和this关键字综合实例解析
2016/12/16 Javascript
nodejs个人博客开发第三步 载入页面
2017/04/12 NodeJs
BootStrap数据表格实例代码
2017/09/13 Javascript
javascript+css3开发打气球小游戏完整代码
2017/11/28 Javascript
React Native 真机断点调试+跨域资源加载出错问题的解决方法
2018/01/18 Javascript
JavaScript实现封闭区域布尔运算的示例代码
2018/06/25 Javascript
vue.js实现会动的简历(包含底部导航功能,编辑功能)
2019/04/08 Javascript
基于JS实现父组件的请求服务过程解析
2019/10/14 Javascript
javascript中的相等操作符(==与===区别)
2019/12/21 Javascript
Python运维之获取系统CPU信息的实现方法
2018/06/11 Python
Python打开文件,将list、numpy数组内容写入txt文件中的方法
2018/10/26 Python
python 多线程中子线程和主线程相互通信方法
2018/11/09 Python
解决python3中的requests解析中文页面出现乱码问题
2019/04/19 Python
Python日期格式和字符串格式相互转换的方法
2020/02/18 Python
python 装饰器的实际作用有哪些
2020/09/07 Python
StubHub巴西:购买和出售您的门票
2016/07/22 全球购物
联想新加坡官方网站:Lenovo Singapore
2017/10/24 全球购物
公司委托书范本
2014/04/04 职场文书
优秀团员事迹材料2000字
2014/08/20 职场文书
大学生职业生涯十年规划书范文
2014/09/17 职场文书
《比尾巴》教学反思
2016/02/24 职场文书
如何用python绘制雷达图
2021/04/24 Python
Vue+TypeScript中处理computed方式
2022/04/02 Vue.js