项目实践:从react-router v3迁移到v4
前言
迁移步骤
React-Router和Redux同步
1. 替换依赖包v3我们引入的是 package.json - "react-router": "^3.0.0",+ "react-router-dom": "^4.1.2", 2. 改写对browserHistory的创建和当前location的获取location.js // v3 import { browserHistory } from 'react-router' // 获取当前location const initialState = browserHistory.getCurrentLocation() ==> // v4 import createHistory from 'history/createBrowserHistory' export const history = createHistory() // Get the current location. const initialState = history.location 这里替换的是history,和当前location的获取方法。在v3,browserHistory存在于
3. 对history绑定监听事件,把location的改变同步到Redux的store中createStore // v3 import { browserHistory } from 'react-router' import { updateLocation } from './location' store.unsubscribeHistory = browserHistory.listen(updateLocation(store))
export const updateLocation = ({ dispatch }) => { return (nextLocation) => dispatch(locationChange(nextLocation)) } 一切似乎都很顺利,接着第一个坑来了 根据 // Listen for changes to the current location. const unlisten = history.listen((location,action) => { // location is an object like window.location console.log(action,location.pathname,location.state) }) 修改 ==> // v4 import { updateLocation,history } from './location' // 监听浏览器history变化,绑定到store。取消监听直接调用store.unsubscribeHistory() store.unsubscribeHistory = history.listen(updateLocation(store)) 接着修改 // v3 // ... import { browserHistory,Router } from 'react-router' // ... <Router history={browserHistory} children={routes} /> ==> // ... import { BrowserRouter,Route } from 'react-router-dom' // ... <BrowserRouter> <div> <Route path='/' component={CoreLayout} /> </div> </BrowserRouter> //... 我们到浏览器中查看,发现URL变化并没有触发 What a f**k! import React from 'react' import PropTypes from 'prop-types' import createHistory from 'history/createBrowserHistory' import { Router } from 'react-router' /** * The public API for a <Router> that uses HTML5 history. */ class BrowserRouter extends React.Component { static propTypes = { basename: PropTypes.string,forceRefresh: PropTypes.bool,getUserConfirmation: PropTypes.func,keyLength: PropTypes.number,children: PropTypes.node } history = createHistory(this.props) render() { return <Router history={this.history} children={this.props.children}/> } } export default BrowserRouter 于是,我们放弃使用 修改 ==> // v4 import { Router,Route } from 'react-router-dom' //... <Router history={history}> <div> <Route path='/' component={CoreLayout} /> </div> </Router> 这样,这个坑算是填上了。也就完成了history和store之间的同步。 重写路由
routes/index.js // v3 //.. export const createRoutes = (store) => ({ path : '/',component : CoreLayout,indexRoute : Home,childRoutes : [ CounterRoute(store),ZenRoute(store),ElapseRoute(store),RouteRoute(store),PageNotFound(),Redirect ] }) //... ==> // ... const Routes = () => ( <Switch> <Route exact path='/' component={Home} /> <Route path='/counter' component={AsyncCounter} /> <Route path='/zen' component={AsyncZen} /> <Route path='/elapse' component={AsyncElapse} /> <Route path='/route/:id' component={AsyncRoute} /> <Route path='/404' component={AsyncPageNotFound} /> <Redirect from='*' to='/404' /> </Switch> ) export default Routes // 这里路由的定义方式由PlainRoute Object改写成了组件嵌套形式,在 代码分割
Counter/index.js // v3 import { injectReducer } from '../../store/reducers' export default (store) => ({ path : 'counter',/* 动态路由 */ getComponent (nextState,cb) { /* 代码分割 */ require.ensure([],(require) => { const Counter = require('./containers/CounterContainer').default const reducer = require('./modules/counter').default /* 将counterReducer注入rootReducer */ injectReducer(store,{ key : 'counter',reducer }) cb(null,Counter) },'counter') } }) 首先,新增 import React from 'react' export default function asyncComponent (importComponent) { class AsyncComponent extends React.Component { constructor (props) { super(props) this.state = { component: null,} } async componentDidMount () { const { default : component } = await importComponent() this.setState({ component: component }) } render () { const C = this.state.component return C ? <C {...this.props} /> : null } } return AsyncComponent }
接着,改写 ==> import { injectReducer } from '../../store/reducers' import { store } from '../../main' import Counter from './containers/CounterContainer' import reducer from './modules/counter' injectReducer(store,reducer }) export default Counter
琐碎API的替换
this.props.router.push('/') ==> this.props.history.push('/') this.props.params.id ==> this.props.match.params.id 总结这里可以看出,使用v4替换v3,对于大型项目并不是一件轻松的事情,有许多小坑要踩,这就是社区很多项目仍然使用v2/v3的原因。笔者认为,v4更符合React的组件思想,于是做了一个实践。最后欢迎指正拍砖,捂脸求star (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |