上一篇介绍了下webpack的一些配置,接下来讲下reactRouter4里面关于路由的一些配置,如何做到模块的按需加载,这也是常用的一种优化网站性能的方式。
前言
react-router 还是 react-router-dom?
首先在创建React项目的时候,我们一般要引入两个包,react 和 react-dom, 那么 react-router 和react-router-dom 是不是两个都要引用呢?其实不然,两者只需取一,不同之处就是后者比前者多出了 Link,BrowserRouter,HashRouter这样的 DOM 类组件。因此我们只需引用 react-router-dom 这个包就行了。当然,如果搭配 redux ,你还需要使用 react-router-redux。 即使是在React Native中, 你也只需要引用react-router-native ,因为react-router-dom和react-router-native都是基于react-router的实现。
实现步骤
一、安装
yarn add react react-dom react-router-dom
这里特别说明下:react版本问题,如果你安装的React是16.9以上版本,那么在你打开控制台的时候会出现以下警告:

-
componentWillMount → UNSAFE_componentWillMount
-
componentWillReceiveProps → UNSAFE_componentWillReceiveProps
-
componentWillUpdate → UNSAFE_componentWillUpdate
React v16.9 不包含破坏性更改,而且旧的生命周期方法在此版本依然沿用,仅此说明下
二、文件创建和babel

在这特别说明下.babelrc文件的作用: babel6.X版本之后,所有的插件都是可插拔的,也就是说只安装babel依然无法正常的工作,我们需要配置对应的.babelrc文件才能起作用。
.babelrc文件需要的配置项主要有预设(presets)和插件(plugins)。
1、预设(presets)的作用是为babel安装指定的插件,插件命名采用babel-preset-xxx的形式;
2、presets是插件plugins的预设,也就是说直接需要不需要的插件一起引入,如果不想使用presets,可以单独使用plugins对某个功能进行单独的引入,有一些方法是presets中不提供的,如果要使用就需要单独引用了。

本人这里用的babel7,关于babel6和babel7的一些不同点,可以参看下这个升级到Babel 7,里面讲的比较细致。
三、router按需加载的实现
在router4之前,我们是使用getComponent的的方式来实现按需加载的,router4中,getComponent方法已经被移除,下面着重介绍一下react-router4是如何来实现按需加载的。
1、router3 的按需加载方式
route3中实现按需加载只需要按照下面代码的方式实现就可以了。
const Home = (location, callback) => {
require.ensure([], require => {
callback(null, require('../Component/Home').default)
},'Home')
}
//配置route
<Route path="home" getComponent={Home} />
2、router4:用create-react-app文档给的react-router按需加载实现
第一步:创建一个异步组件 src/components/AsyncComponent.js
import React from 'react';
export default function (componentFactory) {
class AsyncComponent extends React.Component {
constructor() {
super();
this.state = {component: null};
}
async componentDidMount() {
let {default: component} = await componentFactory();
this.setState({component});
}
render() {
let Comp = this.state.component;
return Comp ? <Comp {...this.props}/> : null;
}
}
return AsyncComponent;
}
第二步:将上面的组件导入router.js, 我这里是src/router/index.js
import React from "react";
import { Route, Switch } from "react-router-dom";
import asyncComponent from "../components/AsyncComponent";
const AsyncHome = asyncComponent(() => import("../pages/Home"));
const AsyncCount = asyncComponent(() => import("../pages/Count"));
const AsyncNotFound = asyncComponent(() => import("../pages/NotFound"));
export default ({ childProps }) =>
<Switch>
<Route
path="/"
exact
component={AsyncHome}
props={childProps}
/>
<Route
path="/count"
exact
component={AsyncCount}
props={childProps}
/>
{/* Finally, catch all unmatched routes */}
<Route component={AsyncNotFound} />
</Switch>;
第三部:封装app根组件, 在scr/App.js下引入router.js
import React, { Component } from "react";
import { Link, withRouter } from "react-router-dom";
import Routes from "./router";
import './assets/reset.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
isAuthenticating: true
};
}
render() {
const childProps = {
isAuthenticated: this.state.isAuthenticated,
userHasAuthenticated: this.userHasAuthenticated
};
return (
<Routes childProps={childProps} />
);
}
}
export default withRouter(App);
第四部:将App组件放至入口文件index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom'
import App from './App';
// import registerServiceWorker from './components/registerServiceWorker';
ReactDOM.render(
<BrowserRouter><App/></BrowserRouter>,
document.getElementById('app')
);
// registerServiceWorker();
以上就是router4的按需加载 在这里补充另外一种实现按需加载的方式:
3、router4: 利用react-loadable这个高级组件实现按需加载
yarn add react-loadable
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable';
const MyLoadingComponent = ({ isLoading, error }) => {
if (isLoading) {
return null;
}
if (error) {
return <div>Sorry, there was a problem loading the page.</div>;
}
return null;
};
const HomeItem = Loadable({
loader: () => import('./pages/Home'),
loading: MyLoadingComponent
});
const CountItem = Loadable({
loader: () => import('./pages/Count'),
loading: MyLoadingComponent
});
const Routes = ({ history }) => (
<Router history={history}>
<Layout>
<Switch>
<Route exact path="/" component={HomeItem} />
<Route exact path="/count" component={CountItem} />
</Switch>
</Layout>
</Router>
);
MyLoadingComponent.propTypes = {
isLoading: PropTypes.bool,
error: PropTypes.bool
};
MyLoadingComponent.defaultProps = {
isLoading: true,
error: false
};
Routes.propTypes = {
history: PropTypes.object
};
Routes.defaultProps = {
history: {}
};
export default Routes;
以上是本人关于webpack4+react16+react-router-dom4从零配置到优化,实现路由按需加载的所有内容了,如果有疑问,或者不对的地方,欢迎大家在下方留言,一起探讨和更正。