微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

React-router 4 按需加载的实现方式及原理详解

React-router 4

介绍了在router4以后,如何去实现按需加载Component,在router4以前,我们是使用getComponent的的方式来实现按需加载的,router4中,getComponent方法已经被移除,下面就介绍一下react-router4是入围和来实现按需加载的。

1.router3的按需加载方式

const about = (location,cb) => {
require.ensure([],require => {
cb(null,require('../Component/about').default)
},'about')
}

//配置route

2.router4按需加载方式(three steps)

one step:

创建Bundle.js文件,这个文件其实是个通过bundle-loader包装后的组件来使用,下面会具体讲这个东西。

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 state mode not undefined,The container will render children
return this.state.mod ? this.props.children(this.state.mod) : null;
}
}

Bundle.propTypes = {
load: PropTypes.func,children: PropTypes.func
};

export default Bundle;

second step:

const A = (props) => (

//这里只是给this.props.child传一个方法,最后在Bundle的render里面调用 {(Container) => } )

third step:

rush:js;"> render() { return (

Welcome!

) }

3.router4按需加载方方式解析

(1).首先解释一下按需加载,通俗的将就是我当前的location在Home,那么我只应该加载Home的东西,而不应该去加载About等等其他的。

(2).Bundle.js这个文件的作用

先看这段代码

rush:js;"> module.exports = function (cb) { __webpack_require__.e/* require.ensure */(2).then((function (require) { cb(__webpack_require__(305)); }).bind(null,__webpack_require__)).catch(__webpack_require__.oe); };

这里是我们通过import loadDashboard from 'bundle-loader?lazy!./containers/A'这种方式引入的container控件。我们使用了bundle-loader将A的源码转化成了上面的代码,具体实现大家可以看bundle-loader源码,代码很少。

上面说到Bundle.js其实就使用来处理这个文件的,这个文件需要一个callback的参数,在Bundle的load方法中,我们会设置这个callback,当路由要调到A Container这里的时候,就回去加载A Container,然后调用这个callback,这个callback会调用setState方法,将我们之前传入的load设置给mod,然后渲染出来。

4.webpack进行bundle-loader统一配置

这里匹配的是src/routers/下面的containers文件夹下面所有的js文件包括二级目录。

rush:js;"> { // 匹配routers下面所有文件 // ([^/]+)\/?([^/]*) 匹配xxx/xxx 或者 xxx test: /containers\/([^/]+)\/?([^/]*)\.jsx?$/,include: path.resolve(__dirname,'src/routers/'),// loader: 'bundle-loader?lazy' loaders: ['bundle-loader?lazy','babel-loader'] }

5.部分源码

1.bundle-loader的源码

rush:js;"> var loaderUtils = require("loader-utils");

module.exports = function() {};
module.exports.pitch = function(remainingRequest) {
this.cacheable && this.cacheable();
var query = loaderUtils.getoptions(this) || {};
if(query.name) {
var options = {
context: query.context || this.options.context,regExp: query.regExp
};
var chunkName = loaderUtils.interpolateName(this,query.name,options);
var chunkNameParam = "," + JSON.stringify(chunkName);
} else {
var chunkNameParam = '';
}
var result;
if(query.lazy) {
result = [
"module.exports = function(cb) {\n"," require.ensure([],function(require) {\n"," cb(require(",loaderUtils.stringifyRequest(this,"!!" + remainingRequest),"));\n"," }" + chunkNameParam + ");\n","}"];
} else {
result = [
"var cbs = [],\n"," data;\n","module.exports = function(cb) {\n"," if(cbs) cbs.push(cb);\n"," else cb(data);\n","}\n","require.ensure([]," data = require(",");\n"," var callbacks = cbs;\n"," cbs = null;\n"," for(var i = 0,l = callbacks.length; i < l; i++) {\n"," callbacksi;\n"," }\n","}" + chunkNameParam + ");"];
}
return result.join("");
}

/*
Output format:

var cbs = [],data;
module.exports = function(cb) {
if(cbs) cbs.push(cb);
else cb(data);
}
require.ensure([],function(require) {
data = require("xxx");
var callbacks = cbs;
cbs = null;
for(var i = 0,l = callbacks.length; i < l; i++) {
callbacksi;
}
});

*/

2.A的源码

rush:js;"> import React from 'react'; import PropTypes from 'prop-types'; import * as reactRedux from 'react-redux'; import BaseContainer from '../../../containers/ReactBaseContainer';

class A extends BaseContainer {
constructor(props) {
super(props);
this.renderCustom = function renderCustom() {
return (

Hello world In A
); }; } render() { // 返回父级view return super.render(); } }

A.propTypes = {
dispatch: PropTypes.func,};

function mapStatetoProps(state) {
return { state };
}

export default reactRedux.connect(mapStatetoProps)(A);

3.route.js的源码

const A = () => (

{Component => } )

const app = () =>

{/* path = "/about" */} {/* "/about/" 可以,但"/about/1"就不可以了 exact 配置之后,需要路径绝对匹配,多个斜杠没有关系,这里直接在浏览器里面设置还有问题*/} {/* path = "/about/" */} {/* "/about/1" 可以,但"/about"就不可以了 用了strict,path要大于等于的关系,少一个斜杠都不行 */} {/* exact 和 strick 都用了就必须一模一样,连斜杠都一样 */} {/* */}
; export default function () { // 用来判断本地浏览器是否支持刷新 const supportsHistory = 'pushState' in window.history; return (
{app()}

);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是深拷贝与浅拷贝?深拷贝与浅拷贝是js中处理对象或数据复制操作的两种方式。‌在聊深浅拷贝之前咱得了解一下js中的两种数据类型:
前言 今天复习了一些前端算法题,写到一两道比较有意思的题:重建二叉树、反向输出链表每个节点 题目 重建二叉树: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 {1,2,4,7,3,5,6,8} 和中序遍历序列 {
最近在看回JavaScript的面试题,this 指向问题是入坑前端必须了解的知识点,现在迎来了ES6+的时代,因为箭头函数的出现,所以感觉有必要对 this 问题梳理一下,所以刚好总结一下JavaScript中this指向的问题。
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高