React-Router4升级之路
最近将React升级到了16.2,也将项目的React-Router升级了v4,我主要说一下我的升级之路。
React 16 新特性
1、render支持了多种的返回类型,例如数组和代码片段等;
2、更好的错误处理,新增componentDidCatch钩子 ;
3、支持自定义DOM属性,属性会透传;
4、体积更小(比15减少了32%),删除了内置的类型检查React.PropTypes;
5、Portals(处理弹窗或者渲染外部dom结构更加方便);
6、性能优化(https://www.itcodemonkey.com/article/1306.html);
上述参考:
http://www.jb51.net/article/127955.htmhttp://blog.csdn.net/lx376693576/article/details/78192768
React Router v4 新特性
1、全组件化
2、修复多次渲染问题
3、新的异步加载方式
安装
下面就以React-Router和最新的React16为例子安装,由于React的API变化不是很大,此处就不多做介绍了。
- 先删除项目中依赖的旧版React和React-Router(如果不删除,升级需要指定版本号)
npm uninstall react react-dom react-router --save
- 安装最新版本(此处的最新版本就是16和4,注意router的包名称是react-router-dom, history是用来访问历史的)
npm install react react-dom react-router-dom history --save
- 查看项目目录下面的package.json
"dependencies": {
"history": "^4.7.2",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-router-dom": "^4.2.2"
}
使用
一、路由的配置方式
先上修改后的代码了
import React from 'react';
import {HashRouter, Route, Switch} from 'react-router-dom';
class App extends Component {
render() {
return (
<HashRouter>
<Switch>
<Route path="/" exact component={BindEmail}/>
<Route path="/bindemail" component={BindEmail}/>
<Route path="/bindemailresult/:type" component={BindEmailResult}/>
<Route path="/updatepassword" component={UpdatePassword}/>
<Route path="/updatemail" component={UpdateMail}/>
<Route component={BindEmail}/>
</Switch>
</HashRouter>
);
}
}
看上面的代码首先要注意几点
1、Router替换成了HashRouter,并且少了一个history的属性,当然你也可以使用BrowserRouter不过需要后台支持。
2、Route中删除了getComponent属性,那我们异步加载怎么办呢,下面会说一下。
3、多了一个Switch组件,以前设置404路由的时候只要在最后加上path="*"
就好了,但是现在只需要在最后加一个路由并且由Switch组件包裹即可。
4、第一行的Route上有一个exact属性,这个属性说明精确匹配,否则所有/开头的组件都会展示/配置的组件(比较绕,可以到时候讲一下)。
5、HashRouter组件内部只能包含一个组件,如果有多个会直接报错。
6、当然了,我们导入的时候只需要导入react-router-dom。
二、异步加载的方式
我们可以使用高阶组件和webpack的import方法进行异步加载js。
- 首先我们得有一个用来加载异步组件的高阶组件,我们暂且称之为"asyncComponent",实现如下:
import React from 'react'
export const asyncComponent = loadComponent => (
class AsyncComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
Component: null
}
}
componentWillMount() {
if (this.hasLoadedComponent()) {
return
}
loadComponent()
// 取到module的default作为组件,因为我们导出组件的时候使用的是 export default
.then(module => module.default)
.then((Component) => {
this.setState({Component})
})
.catch((err) => {
console.error(`Cannot load component in <AsyncComponent />`);
throw err
})
}
hasLoadedComponent() {
return this.state.Component !== null
}
render() {
const {Component} = this.state;
return (Component) ? <Component {...this.props} /> : null
}
}
);
- 我们将需要拆分的js文件,进行下面的处理,import方法会返回一个promise,注意/ * webpackChunkName: "test" * / 这种注释不能删除,它描述了拆分后的文件名称。
import {asyncComponent as async} from './views/async'
// 测试
export const Test = async(() => import(/* webpackChunkName: "test" */ './test'));
// 绑定邮箱
export const BindEmail = async(() => import(/* webpackChunkName: "bindemail" */ './views/bindemail'));
// 修改密码
export const UpdatePassword = async(() => import(/* webpackChunkName: "updatepassword" */ './views/bindemail/updatepassword'));
// 修改邮箱
export const UpdateMail = async(() => import(/* webpackChunkName: "updatemail" */ './views/bindemail/updatemail'));
// 邮箱绑定结果
export const BindEmailResult = async(() => import(/* webpackChunkName: "bindemailresult" */ './views/bindemail/result'));
- 然后我们在路由中直接配置component属性就好了,相比之前会简单一点
<Route path="/bindemail" component={BindEmail}/>
三、可编程路由(路由切换)
- 我们一般会在js中获取路由的参数,我们以前的方式是这样的
this.props.route.params.xxx;
在v4中,会在props上挂载一个match对象,所以获取参数,使用下面的方式
this.props.match.params.xxx
参考:https://reacttraining.com/react-router/web/api/match
- 在代码中切换路由,以前是直接调用hashHistory的方法切换,如
import { hashHistory } from 'react-router';
hashHistory.push('/home');
在v4中将操作历史的工具单独抽离了,也就是history包,API和hashHistory基本一致
import { createHashHistory } from 'history';
const history = createHashHistory();
history.push('/home');
常见问题
低端的浏览器上面可能不支持Map和Set类,会报错:
Map is not undefined
解决方案:
安装core-js,在引入Set,Map相关的语法糖(或许你也可以babel-polyfill,React官方使用的是core-js),如下就可以了
import Map from 'core-js/es6/map';
import Set from 'core-js/es6/set';
// 绑定在window上,就可以全局访问了
window.Map = Map;
window.Set = Set;
参考:
1、https://reactjs.org/docs/javascript-environment-requirements.html
2、https://reacttraining.com/react-router/web/example/basic