【教程】Pastate.js 响应式 react 框架(七)规模化
这是 Pastate.js 响应式 react state 管理框架系列教程,欢迎关注,持续更新。
这一章,我们将介绍 pastate 如何构建大规模应用,以及如何在原生 redux 项目中使用等。
路由
当我们的应用日益复杂时,需要用前端路由的模式来管理多个界面。
无参数路由
Pastate 应用可以与通用的 react-router 路由框架配合使用。我们还是以 班级信息管理系统 为例来介绍如何在 pastate 中使用路由,我们接下来把学生板块和课程板块分别放在 /student 和 /class 路由目录下。
首先安装 react-router 的网页版 react-router-dom:
$ npm install react-router-dom --save 或 $ yarn add react-router-dom
使用 Router 作为根容器
接着我们用路由 Router 组件作为新的根容器来包装我们的原来的根容器 Navigator,代码如下:src/index.js
...
import { BrowserRouter as Router } from 'react-router-dom';
ReactDOM.render(
    makeApp(        <Router>
            <Navigator.view />
        </Router>,
        storeTree
    ),
    document.getElementById('root')
);使用 Route 组件来定义路由
接下来,我们来看看导航模块 Navigator 的视图如何修改:Navigator.view.js
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 处修改
- 使用路由组件 - Switch+- Route来代替之前手动判断渲染子模块的代码,让路由自动根据当前 url 选择对应的子组件来显示;
- 使用路由组件 - NavLink来代替之前的导航栏按钮,把每个 tab 绑定到一个特定的 url;
- 使用路由的 withRouter 函数包装我们原来生成的 container,这使得当路由变化时,container 会收到通知并重新渲染 
完成!这时我们就可以看到,当我们切换导航标签时,url 和显示的子组件同时改变:
路由生效
当我们在 /class 路径下刷新或进入时,应用可以显示为课程板块,这是路由组件为我们提供的一个在原来的无路由模式中没有的功能。
我们这里使用的是 BrowserRouter 对应的 browserHistory ,因此在 url 中是不用 HashRouter 的 hashHistory 模式下的 # 分割符来分割前端和后端路由,所以在服务器端需要做一些相关配置,把这些路径都路由到相同的一个HTML应用。如果后端难以配合修改,你可以使用 HashRouter 代替我们上面的 BrowserRouter:
// index.jsimport {  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.jslet selected = this.props.match.params.id;
在 actions 中使用路由
如果你要在 actions 中简单地获取当前网址的路径信息,你可以直接使用 window.location 获取:
// StudentPanel.model.jsconst 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.jsconst 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 告诉我们。
嵌入 redux 应用
Pastate 内部使用 redux 作为默认的多模块引擎,这意味着,你可以在原生的 redux 项目中使用 pastate 模块, 只需两步:
- 使用 Pastate 模块的 store 中提供的 getReduxReducer 获取该模块的 redux reducer,并把它挂载到 redux 的 reducerTree 中; 
- 把 redux 的 store 实例的 dispatch 注入 astate 模块的 store 的 dispatch 属性 。 
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
使用 redux devtools 不要求 你把 pastate 嵌入到原生 redux 应用中,你不需要懂得什么是 redux,在纯 pastate 项目中就可以使用 redux devtools!
中间件
内置中间件
Pastate 目前实现了基于 actions 的中间件系统,可用于对 actions 的调用进行前置或后置处理。Pastate 内置了几个实用的中间件生成器:
- logActions(time: boolean = true, spend: boolean = true, args: boolean = true): 把 actions 的调用情况 log 到控制台 
- syncActions(onlyMutations: boolean = false): 把每个 action 都转化为同步 action, 方便互相调用时的调试观察每个 action 对数据的改变情况 
- dispalyActionNamesInReduxTool(onlyMutations: boolean = false): 把 actions 名称显示在 redux devtools 中,方便调试 
自定义中间件
你也可以很轻松的定义中间件,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 包结构
下一章,我们来详细介绍 pastate 的原理。
作者:伟小鹏
链接:https://www.jianshu.com/p/cc3668fbe52f
共同学习,写下你的评论
评论加载中...
作者其他优质文章
 
                 
            



 
			 
					 
					