【教程】Pastate.js 响应式 react 框架(七)规模化

这是 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 做为根容器

接着咱们用路由 Router 组件做为新的根容器来包装咱们的原来的根容器 Navigator,代码以下:
src/index.jsgithub

...
import { BrowserRouter as Router } from 'react-router-dom';

ReactDOM.render(
    makeApp(
        <Router>
            <Navigator.view />
        </Router>,
        storeTree
    ),
    document.getElementById('root')
);

使用 Route 组件来定义路由

接下来,咱们来看看导航模块 Navigator 的视图如何修改:
Navigator.view.jsweb

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;
  • 使用路由的 withRouter 函数包装咱们原来生成的 container,这使得当路由变化时,container 会收到通知并从新渲染

完成!这时咱们就能够看到,当咱们切换导航标签时,url 和显示的子组件同时改变:redux

路由生效

当咱们在 /class 路径下刷新或进入时,应用能够显示为课程板块,这是路由组件为咱们提供的一个在原来的无路由模式中没有的功能。segmentfault

咱们这里使用的是 BrowserRouter 对应的 browserHistory ,所以在 url 中是不用 HashRouter 的 hashHistory 模式下的 # 分割符来分割前端和后端路由,因此在服务器端须要作一些相关配置,把这些路径都路由到相同的一个HTML应用。若是后端难以配合修改,你可使用 HashRouter 代替咱们上面的 BrowserRouter:

// index.js
import {  HashRouter as Router } from 'react-router-dom';

这是就会自动启用 # (hash路由)来分割前端和后端路由:

启用 code#/code 来分割前端和后端路由

有参数路由

咱们在上面的路由不涉及参数,若是咱们须要使用相似 \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 中使用路由

若是你要在 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 告诉咱们。

嵌入 redux 应用

Pastate 内部使用 redux 做为默认的多模块引擎,这意味着,你能够在原生的 redux 项目中使用 pastate 模块, 只需两步:

  1. 使用 Pastate 模块的 store 中提供的 getReduxReducer 获取该模块的 redux reducer,并把它挂载到 redux 的 reducerTree 中;
  2. 把 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 的原理。

相关文章
相关标签/搜索