摘要:詳見對綁定監聽事件,把的改變同步到的中用來把的更新同步到中。代碼分割版本通過和實現代碼分割和動態路由。筆者認為,更符合的組件思想,于是做了一個實踐。
前言原文:https://github.com/YutHelloWo...
遷移步驟今年3月初發布了react-router v4,相較之前的v3和v2版本做了一個破壞性的升級。遵循一切皆React Component的理念。靜態路由變成了動態路由。這里記錄下v3項目如何遷移到v4。
項目地址:https://github.com/YutHelloWo...
對React-Router和Redux同步進行重構
重寫路由
代碼分割
瑣碎的API替換
React-Router和Redux同步詳細代碼參閱這個PR
1. 替換依賴包這里我們仍然不使用react-router-redux這個庫。為了和react-routerv4版本保持一致,react-router-redux發布了v5.0.0版本,你當然也可以使用它來實現這個功能。
v3我們引入的是react-router包,在v4我們只引入react-router-dom這個包。安裝react-router-dom時會同時安裝history。
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存在于react-router中,而v4把history抽離了出來,提供了createBrowserHistory ,createHashHistory ,createMemoryHistory 三種創建history的方法。v4中創建的history導出,在后面會需要用到。
3. 對history綁定監聽事件,把location的改變同步到Redux的store中history API詳見: https://github.com/ReactTrain...
createStore
// v3 import { browserHistory } from "react-router" import { updateLocation } from "./location" store.unsubscribeHistory = browserHistory.listen(updateLocation(store))
updateLocation用來把location的更新同步到store中。
export const updateLocation = ({ dispatch }) => { return (nextLocation) => dispatch(locationChange(nextLocation)) }
一切似乎都很順利,接著第一個坑來了
根據historyAPI提供的
// 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) })
修改createStore.js
==>
// v4 import { updateLocation, history } from "./location" // 監聽瀏覽器history變化,綁定到store。取消監聽直接調用store.unsubscribeHistory() store.unsubscribeHistory = history.listen(updateLocation(store))
接著修改app.js
// v3 // ... import { browserHistory, Router } from "react-router" // ...
==>
// ... import { BrowserRouter, Route } from "react-router-dom" // ...//...
我們到瀏覽器中查看,發現URL變化并沒有觸發updateLocation(store),state并沒有變化。
What a f**k!
問題出在BrowserRouter在創建的時候在內部已經引入了一個history,updateLocation(store)應該監聽的是內部的這個history。這里貼下BrowserRouter.js的代碼
import React from "react" import PropTypes from "prop-types" import createHistory from "history/createBrowserHistory" import { Router } from "react-router" /** * The public API for athat 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 } } export default BrowserRouter
于是,我們放棄使用BrowserRouter,而使用Router。
修改app.js
==>
// v4 import { Router, Route } from "react-router-dom" //...
這樣,這個坑算是填上了。也就完成了history和store之間的同步。
重寫路由v4取消了PlainRoute 中心化配置路由。Route是一個react component。
取消了IndexRoute,通過Switch來組件提供了相似的功能,當被渲染時,它僅會渲染與當前路徑匹配的第一個子 。
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 = () => () export default Routes //
這里路由的定義方式由PlainRoute Object改寫成了組件嵌套形式,在PageLayout.js中插入
v3版本通過getComponet和require.ensure實現代碼分割和動態路由。在v4版本,我們新增異步高階組件,并使用import()替代require.ensure()
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") } })
首先,新增AsyncComponent.js
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 ?: null } } return AsyncComponent }
這個asyncComponent 函數接受一個importComponent 的參數,importComponent 調用時候將動態引入給定的組件。
在componentDidMount 我們只是簡單地調用importComponent 函數,并將動態加載的組件保存在狀態中。
最后,如果完成渲染,我們有條件地提供組件。在這里我們如果不寫null的話,也可提供一個菊花圖,代表著組件正在渲染。
接著,改寫Counter/index.js
==>
import { injectReducer } from "../../store/reducers" import { store } from "../../main" import Counter from "./containers/CounterContainer" import reducer from "./modules/counter" injectReducer(store, { key : "counter", reducer }) export default Counter
瑣碎API的替換一旦加載Counter/index.js,就會把counterReducer注入到Rudecer中,并加載Counter組件。
v4 移除了onEnter onLeave等屬性,history替換router屬性,新增match
this.props.router.push("/")
==>
this.props.history.push("/")
this.props.params.id
==>
this.props.match.params.id總結
這里可以看出,使用v4替換v3,對于大型項目并不是一件輕松的事情,有許多小坑要踩,這就是社區很多項目仍然使用v2/v3的原因。筆者認為,v4更符合React的組件思想,于是做了一個實踐。最后歡迎指正拍磚,捂臉求star ? 。
參考Code Splitting in Create React App
Migrating from v2/v3 to v4
React-Router
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84747.html
摘要:概述相對于幾乎是重寫了新版的更偏向于組件化。汲取了很多思想,路由即是組件,使路由更具聲明式,且方便組合。如果你習慣使用,那么一定會很快上手新版的。被一分為三。不止是否有意義參考資料遷移到關注點官方文檔 概述 react-router V4 相對于react-router V2 or V3 幾乎是重寫了, 新版的react-router更偏向于組件化(everything is comp...
摘要:前言最近將公司項目的從版本升到了版本,跟完全不兼容,是一次徹底的重寫。升級過程中踩了不少的坑,也有一些值得分享的點。沒有就會匹配所有路由最后不得不說升級很困難,坑也很多。 前言 最近將公司項目的 react-router 從 v3 版本升到了 v4 版本,react-router v4 跟 v3 完全不兼容,是一次徹底的重寫。這也給升級造成了極大的困難,與其說升級不如說是對 route...
摘要:中的包中的包主要有三個和。的理念上面提到的理念是一切皆組件以下統一稱組件。從這點來說的確方便了不少,也迎合一切皆組件的理念。組件是中主要的組成單位,可以認為是或的路由入口。將該標示為嚴格匹配路由。的屬性追加一條。 2019年不知不覺已經過去19天了,有沒有給自己做個總結?有沒有給明年做個計劃?當然筆者已經做好了明年的工作、學習計劃;同時也包括該系列博客剩下的博文計劃,目前還剩4篇:分別...
摘要:使用了約等于才能匹配或者能匹配,所以說是約等于。使用了和才能匹配后續補充這是版本中新添加,主要用來做唯一匹配的功能。就是想要在眾多路由中只匹配其中一個路由。 React-Router v4 一. Switch 、Router 、Route三者的區別 1、Route Route 是建立location 和 ui的最直接聯系 2、Router react-router v4 中,Route...
摘要:項目問題總結這個項目,很簡單,前端使用,后端使用進行開發。方便移動端開發。當動畫結束后,有一個鉤子函數可以使用其他一些功能組件,都是自己嘗試去編寫的,像日歷組件組件組件等。版本的,是沒有任何的鉤子函數,我就感覺懵逼了。。。 todo-list 項目問題總結 這個 todo-list 項目,很簡單,前端使用 react,后端 nodejs 使用 koa2 進行開發。數據庫使用 Mysql...
閱讀 4620·2021-10-25 09:48
閱讀 3212·2021-09-07 09:59
閱讀 2167·2021-09-06 15:01
閱讀 2693·2021-09-02 15:21
閱讀 2732·2019-08-30 14:14
閱讀 2184·2019-08-29 13:59
閱讀 2514·2019-08-29 11:02
閱讀 2533·2019-08-26 13:33