Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
Redux 是在 Flux 的基础上产生的,基本思想是保证数据的单向流动,同时便于控制、使用、测试。Redux 并不依赖于其它 JavaScript 库。
随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。
跟随 Flux、CQRS 和 Event Sourcing 的脚步,通过限制更新发生的时间和方式,Redux 试图让 state 的变化变得可预测。这些限制条件反映在 Redux 的三大原则中:
Redux 主要分为三个部分 Action、Reducer、及 Store
严格的单向数据流是 Redux 架构的设计核心。store.dispatch(action) -> reducer(state, action) -> store.getState() 构成了一个“单向数据流”。
Redux 应用中数据的生命周期遵循下面 4 个步骤:
Flux 是一种应用架构,或者说是一种思想,它跟 React 本身没什么关系,它可以用在 React 上,也可以用在别的框架上。
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” 的普通对象来对更改进行描述。不同的是:
应用中所有的 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' ] // }