這是 Pastate.js 響應式 react state 管理框架系列教程,歡迎關注,持續更新。 javascript
這一章,咱們將介紹 pastate 如何構建大規模應用,以及如何在原生 redux 項目中使用等。前端
當咱們的應用日益複雜時,須要用前端路由的模式來管理多個界面。java
Pastate 應用能夠與通用的 react-router 路由框架配合使用。咱們仍是以 班級信息管理系統 爲例來介紹如何在 pastate 中使用路由,咱們接下來把學生板塊和課程板塊分別放在 /student 和 /class 路由目錄下。react
首先安裝 react-router 的網頁版 react-router-dom:git
$ npm install react-router-dom --save 或 $ yarn add react-router-dom
接着咱們用路由 Router 組件做爲新的根容器來包裝咱們的原來的根容器 Navigator,代碼以下: src/index.js
github
... import { BrowserRouter as Router } from 'react-router-dom'; ReactDOM.render( makeApp( <Router> <Navigator.view /> </Router>, storeTree ), document.getElementById('root') );
接下來,咱們來看看導航模塊 Navigator 的視圖如何修改: Navigator.view.js
web
import { Route, Redirect, Switch, withRouter, NavLink } from 'react-router-dom' class Navigator extends React.PureComponent{ render(){ /** @type {initState} */ const state = this.props.state; return ( <div> <div className="nav"> <div className="nav-title">班級信息管理系統</div> <div className="nav-bar"> <NavLink className="nav-item" activeClassName="nav-item-active" to="/student" > 學生({this.props.count.student}) </NavLink> <NavLink className="nav-item" activeClassName="nav-item-active" to="/class" > 課程({this.props.count.class}) </NavLink> </div> </div> <div className="main-panel"> <Switch> <Redirect exact from='/' to='/student'/> <Route path="/student" component={StudentPanel.view}/> <Route path="/class" component={ClassPanel.view}/> </Switch> </div> </div> ) } } export default withRouter(makeContainer(Navigator, state => ({...})))
咱們對該文件進行了 3 處修改npm
Switch
+ Route
來代替以前手動判斷渲染子模塊的代碼,讓路由自動根據當前 url 選擇對應的子組件來顯示;NavLink
來代替以前的導航欄按鈕,把每一個 tab 綁定到一個特定的 url;完成!這時咱們就能夠看到,當咱們切換導航標籤時,url 和顯示的子組件同時改變:redux
當咱們在 /class
路徑下刷新或進入時,應用能夠顯示爲課程板塊,這是路由組件爲咱們提供的一個在原來的無路由模式中沒有的功能。segmentfault
咱們這裏使用的是 BrowserRouter 對應的 browserHistory
,所以在 url 中是不用 HashRouter 的 hashHistory
模式下的 #
分割符來分割前端和後端路由,因此在服務器端須要作一些相關配置,把這些路徑都路由到相同的一個HTML應用。若是後端難以配合修改,你可使用 HashRouter
代替咱們上面的 BrowserRouter
:
// index.js import { HashRouter as Router } from 'react-router-dom';
這是就會自動啓用 #
(hash路由)來分割前端和後端路由:
咱們在上面的路由不涉及參數,若是咱們須要使用相似 \student\1
、\student\2
的方式來表示目前顯示哪個 index 或 id 的學生,咱們能夠在定義路由時使用參數:
// Navigator.view.js <Route path="/student/:id" component={StudentPanel.view}/>
並在被路由的組件的 view 中這樣獲取參數:
// StudentPanel.view.js let selected = this.props.match.params.id;
若是你要在 actions 中簡單地獲取當前網址的路徑信息,你能夠直接使用 window.location
獲取:
// StudentPanel.model.js const actions = { handleClick(){ console.log(window.location) console.log(window.location.pathname) // 當使用 BrowserRouter 時 console.log(window.location.hash) // 當使用 HashRouter 時 } }
若是你須要在 actions 獲取和更改路由信息,如跳轉頁面等,你能夠在 view 視圖中把 this.props.history 傳入 action, 並經過 history 的 API 獲取並修改路由信息:
// StudentPanel.model.js const actions = { selectStudent(history, index){ console.log(history) history.push(index+'') // history.push('/student/' + index) // history.goBack() // or .go(-1) } }
通過基礎的測試,pastate 兼容 react-router 的路由參數、history 等功能,若是你發現問題,請提交 issue 告訴咱們。
若是你對開發調試體驗的要求很是高,要實現 「Keep your state in sync with your router」, 以支持用開發工具來實現高級調試,能夠參考 react-router-redux 把路由功能封裝爲一個只有 store 而沒有 veiw 的 pastate 服務模塊, 並掛載到 storeTree。若是你作了,請提交 issue 告訴咱們。
Pastate 內部使用 redux 做爲默認的多模塊引擎,這意味着,你能夠在原生的 redux 項目中使用 pastate 模塊, 只需兩步:
import { createStore, combineReducers } from 'redux'; import { makeApp, combineStores } from 'pastate'; ... import * as StudentPanel from './StudentPanel'; const reducerTree = combineReducers({ panel1: oldReducer1, panel2: oldReducer2, panel3: StudentPanel.store.getReduxReducer() // 1. 獲取 Pastate 模塊的 reducer 並掛載到你想要的位置 }) let reduxStore = createStore(reducerTree) StudentPanel.store.dispatch = reduxStore.dispatch // 2. 把 redux 的 dispatch 注入 Pastate 模塊中
完成!這時你就能夠在 redux 應用中漸進式地使用 pastate 啦!
若是你在使用 dva.js 等基於 redux 開發的框架,一樣能夠用這種方式嵌入 pastate 模塊。
因爲 pastate 內部使用 redux 做爲多模塊引擎,因此你能夠直接使用 redux devtools 做爲 pastate 應用的調試工具。Pastate 對其作了友好支持,你無需任何配置,就能夠直接打開 redux devtools 來調試你的應用:
使用 redux devtools 不要求 你把 pastate 嵌入到原生 redux 應用中,你不須要懂得什麼是 redux,在純 pastate 項目中就可使用 redux devtools!
Pastate 目前實現了基於 actions 的中間件系統,可用於對 actions 的調用進行前置或後置處理。Pastate 內置了幾個實用的中間件生成器:
你也能夠很輕鬆的定義中間件,pastate 中間件定義方式和 koa 中間件相似,例如咱們定義一個簡單的 log 中間件:
const myLogMiddleware = function (ctx, next) { let before = Date.now(); next(); console.log(ctx.name + ': '+ (Date.now() - before) + 'ms'); }
ctx
參數是上下文(context)對象,包括以下屬性:type MiddlewareContext = { name: string, // action 的名稱 agrs?: IArguments, // action 的調用參數 return: any, // action 的返回值 store: XStore // action 綁定的 store }
next
參數是下一個中間件或已作參數綁定的 action 實體, 你能夠實現本身的中間件邏輯,決定要不要調用或在何時調用 next。Pastate 推薦使用 create-react-app 來做爲應用的初始化和開發工具,create-react-app 不僅是一個簡單的 react 應用模板,它還爲咱們提供了很是完善的 react 開發支持,詳見其文檔。
在 pastate 應用中,你能夠簡單的使用默認的 build 指令來編譯應用:
$ npm run build 或 $ yarn build
其餘編譯和部署方式請參考這裏。
Pastate 在編譯以後僅爲 ~28kb, gzip 以後僅爲 ~9kb,很是輕便。Pastate 包的總體結構以下(圖中顯示的是未 gzip 的大小):
下一章,咱們來詳細介紹 pastate 的原理。