转载

扩展微信小程序框架功能(5):Redux

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

Redux 是在 Flux 的基础上产生的,基本思想是保证数据的单向流动,同时便于控制、使用、测试。Redux 并不依赖于其它 JavaScript 库。

Redux

随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。

跟随 Flux、CQRS 和 Event Sourcing 的脚步,通过限制更新发生的时间和方式,Redux 试图让 state 的变化变得可预测。这些限制条件反映在 Redux 的三大原则中:

  • 单一数据源。整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
  • State 是只读的。唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
  • 使用纯函数来执行修改。为了描述 action 如何改变 state tree ,你需要编写 reducers。

扩展微信小程序框架功能(5):Redux

Redux 主要分为三个部分 Action、Reducer、及 Store

  • Action。Action 很简单,就是一个单纯的包含 { type, payload } 的对象,type 是一个常量用来标示动作类型,payload 是这个动作携带的数据。Action 需要通过 store.dispatch() 方法来发送。
  • Reducer。Reducer 用来处理 Action 触发的对状态树的更改。所以一个 reducer 函数会接受 oldState 和 action 两个参数,返回一个新的 state:(oldState, action) => newState。
  • Store。Store 的作用就是连接Action 和 Reducer,Store 的作用有这么几个:Hold 住整个应用的 State 状态树;提供一个 getState() 方法获取 State;提供一个 dispatch() 方法发送 action 更改 State;提供一个 subscribe() 方法注册回调函数监听 State 的更改

严格的单向数据流是 Redux 架构的设计核心。store.dispatch(action) -> reducer(state, action) -> store.getState() 构成了一个“单向数据流”。

Redux 应用中数据的生命周期遵循下面 4 个步骤:

  • 调用 store.dispatch(action)。
  • Redux store 调用传入的 reducer 函数。
  • 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。
  • Redux store 保存了根 reducer 返回的完整 state 树。

Redux 与 Flux

Flux 是一种应用架构,或者说是一种思想,它跟 React 本身没什么关系,它可以用在 React 上,也可以用在别的框架上。

扩展微信小程序框架功能(5):Redux Flux 主要包括四个部分,Dispatcher、Store、View、Action,其中 Dispatcher 是 Flux 的核心枢纽,它相当于是一个事件分发器,将那些分散在各个组件里面的逻辑代码收集起来,统一在 Dispatcher 中进行处理。

完整的 Flux 处理流程是这样的:用户通过与 view 交互或者外部产生一个 Action,Dispatcher 接收到 Action 并执行那些已经注册的回调,向所有 Store 分发 Action。通过注册的回调,Store 响应那些与他们所保存的状态有关的 Action。然后 Store 会触发一个 change 事件,来提醒 controller-views 数据已经发生了改变。Controller-views 监听这些事件并重新从 Store 中获取数据。这些 controller-views 调用他们自己的 setState() 方法,重新渲染自身以及组件树上的所有后代组件。

Redux 的灵感来源于 Flux 的几个重要特性,它可以看作是 Flux 的一种实现。和 Flux 一样,Redux 规定,将模型的更新逻辑全部集中于一个特定的层,都不允许程序直接修改数据,而是用一个叫作 “action” 的普通对象来对更改进行描述。不同的是:

  • Redux 只有一个 store。 Flux 里面会有多个 store 存储应用数据,并在 store 里面执行更新逻辑,当 store 变化的时候再通知 controller-view 更新自己的数据,Redux 将各个 store 整合成一个完整的 store,并且可以根据这个 store 推导出应用完整的 state。同时 Redux 中更新的逻辑也不在 store 中执行而是放在 reducer 中。
  • Redux 没有 Dispatcher。Redux 中没有 Dispatcher 的概念,它使用 reducer 来进行事件的处理,reducer 是一个纯函数,这个函数被表述为 (previousState, action) => newState,它根据应用的状态和当前的 action 推导出新的 state。Redux 中有多个 reducer,每个 reducer 负责维护应用整体 state 树中的某一部分,多个 reducer 可以通过 combineReducers 方法合成一个根reducer,这个根reducer负责维护完整的 state,当一个 action 被发出,store 会调用 dispatch 方法向某个特定的 reducer 传递该 action,reducer 收到 action 之后执行对应的更新逻辑然后返回一个新的 state,state 的更新最终会传递到根reducer处,返回一个全新的完整的 state,然后传递给 view。

Redux使用

应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。唯一改变 state 的办法是触发 action,一个描述发生什么的对象。

为了描述 action 如何改变 state 树,需要编写 reducers。

   // 这是一个 reducer,形式为 (state, action) => state 的纯函数。
    function counter(state = 0, action) {        switch (action.type) {            case 'INCREMENT':                return state + 1;            case 'DECREMENT':                return state - 1;            default:                return state;
        }
    }    // 创建 Redux store 来存放应用的状态
    let store = createStore(counter);    // 可以手动订阅更新,也可以事件绑定到视图层。
    store.subscribe(() =>        console.log(store.getState())
    );    // 改变内部 state 唯一方法是 dispatch 一个 action。
    store.dispatch({ type: 'INCREMENT' }); // 输出:1        
    store.dispatch({ type: 'INCREMENT' }); // 输出:2
    store.dispatch({ type: 'DECREMENT' }); // 输出:1

以上代码,首先定义改变应用状态的对象,这个对象被叫做 action,而不是直接改变 state。然后编写专门的函数来决定每个 action 如何改变应用的 state,这个函数被叫做 reducer。

Redux只有一个单一的 store 和一个根级的 reduce 函数(reducer)。

随着应用越来越大,一方面,不能把所有的数据都放到一个reducer里面,另一方面,为每个reducer创建一个store,后续store的维护就显得比较麻烦。combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。合并后的 reducer 可以调用各个子 reducer,并把它们的结果合并成一个 state 对象。state 对象的结构由传入的多个 reducer 的 key 决定。

   // 创建两个reducer
    function todos(state = [], action) {        switch (action.type) {            case 'ADD_TODO':                return state.concat([action.text])            default:                return state
        }
    }    function counter(state = 0, action) {        switch (action.type) {            case 'INCREMENT':                return state + 1
            case 'DECREMENT':                return state - 1
            default:                return state
        }
    }    // 将多个reducer合并成一个
    var combineReducers = require('../../lib/redux/redux').combineReducers;    var rootReducer = combineReducers({
        todos,
        counter
    });    var createStore = require('../../lib/redux/redux').createStore;    var store = createStore(rootReducer);    console.log(store.getState())    // {
    //   counter: 0,
    //   todos: []
    // }
    store.dispatch({
        type: 'ADD_TODO',
        text: 'Use Redux'
    });    // {
    //   counter: 0,
    //   todos: [ 'Use Redux' ]
    // }

参考资料

  • Redux
  • Redux@github
  • Redux 中文文档
  • 微信小程序集成 Redux
  • 解读redux工作原理
  • 浅谈 React、Flux 与 Redux
  • Redux 卍解

其他

  • 完整代码:https://github.com/guyoung/GyWxappCases/tree/master/Enhance
  • 微信小程序Canvas增强组件WeZRender:https://github.com/guyoung/WeZRender
原文  http://mp.weixin.qq.com/s?__biz=MzI0ODU5Mzg0NA==&mid=2247483713&idx=1&sn=c652e5020adc9436d0d138db4ae783d7&chksm=e99f2d9adee8a48c3ffd2f22e85a3507d3a4805f06a4f7c32687d2daeef5c2937c5b35bd40ec
正文到此结束
Loading...