这是 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 的原理。