Redux 是管理应用状态的js库。是单向数据流应用架构的一种比较优雅的实现。javascript
Redux 和 React 之间没有关系。Redux 支持 React、Angular、Ember、jQuery 甚至纯 JavaScript。Redux 无依赖。html
三大原则java
state 以单一对象存储在 store 对象中。git
state是只读的:这里和Flux思想一致。惟一改变 state 的方法是触发事先定义好的 action。es6
使用纯函数 reducer 执行 state 更新。github
三大概念redux
Action数据结构
Reducer架构
Storeapp
Actions are payloads of information that send data from your application to your store. They are the only source of information for the store. You send them to the store using store.dispatch().
Action 一般只是描述某一特定事情。例若有一个加入购物车的 action:
{ type: 'ADD_CART', goods: { ... } }
一般状况下,咱们会使用建立函数(Action Creater)返回 Action 对象。
const ADD_CART = 'ADD_CART'; function addToCart(goods) { return { type: ADD_CART, goods }; }
惟一改变 state 的方法是触发事先定义好的 action。
state = store.getState(); store.dispatch(addToCart(goods)); state = store.getState();
Actions describe the fact that something happened, but don’t specify how the application’s state changes in response. This is the job of a reducer.
Reducer 是什么呢,Reducer 是用来处理数据逻辑的,具体就是根据 Action 处理 State 的函数。
(previousState, action) => newState
Action 并无指出应用要如何更新购物车对应的 State。怎么更新 State 就是 reducer 要作的事情了。
编写 reducer 前须要肯定页面或应用的 state,state 结构肯定后 reducer 就出来了。
这里有两个问题:
一、怎样设计 state 的数据结构?
二、有了 state 结构,怎么编写 reducer?
在 Redux 应用中,全部的 state 都被保存在一个单一对象中(这点跟官方的Flux实现不同)。以最简的形式把应用的 state 用对象描述出来(这点跟官方的Flux实现同样)。
一般,这个 state 树还须要存放其它一些数据,例如 UI 相关的 state。这样作没问题,但尽可能把这些数据与 UI 相关的 state 分开。
例如 state 结构以下:
{ goods:{}, carts: [{ ... }, { ... }], comments: [{ ... }, { ... }] //相关的 UI state }
对于上面的结构编写对应的 reducer 就相似:
function app(state = initialState, action) {//这里一个技巧是使用 ES6 参数默认值语法 来精简代码。 switch (action.type) { case 'ACTION_NAME1': //处理state //注意1:返回 新的状态,不要修改 state。 应该新建了一个副本。 return newState; case 'ACTION_NAME1': //处理state 返回 新的状态 return newState; default://注意2:在 default 状况下返回旧的 state, 若是没有旧的状态就返回初始状态 initialState return state; } }
而 reducer 是能够拆分和合成的。真正开发项目的时候 State 会涉及不少功能,在一个 reducer 中处理全部逻辑会很是混乱,因此须要拆分红多个小 reducer,
每一个 reducer 只处理它管理的那部分State数据。因此根据 state 的结构调整拆分上面的 reducer :
function goods(state = Map(), action) { switch (action.type) { case types.INIT_GOODS: state = Immutable.fromJS(action.goods); return state; case types.SET_GOODS_COLLECT: state = state.update('isCollect', v=>!v); state = state.update('collectNum', v=> (state.get('isCollect') ? v + 1 : v - 1)); return state; default: return state; } } function comments(state = List(), action) { switch (action.type) { case types.INIT_COMMENTS: state = Immutable.fromJS(action.comments); return state; case types.GET_MORE_COMMENT: action.comments.map(function(item) { state = state.push(item); }); return state; default: return state; } } function carts(state = List(), action) { switch (action.type) { case types.INIT_CARTS: state = Immutable.fromJS(action.carts); return state; case types.ADD_CART: state = Immutable.fromJS(action.carts); return state; default: return state; } }
redux 提供 combineReducers() 函数来调用咱们编写的一系列 reducer,每一个 reducer 根据它们的 key 来筛选出 state 中的一部分数据并处理,而后这个生成的函数所全部 reducer 的结果合并成一个大的对象。
const rootReducer = combineReducers({ goods, comments, carts }); export default rootReducer;
至此根据 state 结构编写 reducer 完成。
action 用来描述“发生了什么”, reducers 会根据 action 更新 state。
Store 就是把它们联系到一块儿的对象,是用来维持应用的 state 的。
store有四个方法。
getState: 获取应用当前 state。
subscribe:添加监听器。
dispatch:分发 action。更新 state。
replaceReducer:替换 store 当前用来处理 state 的 reducer。
经常使用的是dispatch,这是修改State的惟一途径,使用起来也很是简单。
Redux 应用只有一个单一的 store。当须要拆分处理数据的逻辑时,使用 reducer 组合 而不是建立多个 store。而官方的 Flux 实现,则是一个应用能够有一个或多个 store, Flux 中 store 的划分可大可小。
建立一个 store :
let store = createStore(rootReducers, initialState);
获取 state :
store.getState();
更新 state :
store.dispatch(addToCart(goods));
example.js http://rackt.org/redux/
import { createStore } from 'redux' /** * This is a reducer, a pure function with (state, action) => state signature. * It describes how an action transforms the state into the next state. * * The shape of the state is up to you: it can be a primitive, an array, an object, * or even an Immutable.js data structure. The only important part is that you should * not mutate the state object, but return a new object if the state changes. * * In this example, we use a `switch` statement and strings, but you can use a helper that * follows a different convention (such as function maps) if it makes sense for your project. */ function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } // Create a Redux store holding the state of your app. // Its API is { subscribe, dispatch, getState }. let store = createStore(counter) // You can subscribe to the updates manually, or use bindings to your view layer. store.subscribe(() => console.log(store.getState()) ) // The only way to mutate the internal state is to dispatch an action. // The actions can be serialized, logged or stored and later replayed. store.dispatch({ type: 'INCREMENT' }) // 1 store.dispatch({ type: 'INCREMENT' }) // 2 store.dispatch({ type: 'DECREMENT' }) // 1
example2.js
import { combineReducers, createStore } from 'redux' var objectAssign = require('object-assign'); // Action const ADD_CART = 'ADD_CART'; const SET_GOODS_COLLECT = 'SET_GOODS_COLLECT'; function addToCart(goods) { return { type: ADD_CART, goods }; } function collectGoods() { return { type: SET_GOODS_COLLECT }; } // reducers var initGoods = {"id": 123, "name": "星战正版机器人BB-8", isCollect: false}; function goods(state = initGoods, action) { switch (action.type) { case SET_GOODS_COLLECT: return objectAssign({}, state, {isCollect: !state.isCollect}); default: return state; } } var initCarts = []; function carts(state = initCarts, action) {//es6 特性 switch (action.type) { case ADD_CART: return [...state, action.goods];//es6 特性 default: return state; } } const rootReducer = combineReducers({ goods, carts }); let store = createStore(rootReducer); console.log(store.getState()); store.dispatch(collectGoods()); console.log(store.getState()); store.dispatch(addToCart({"id": 124, "name": "星战正版机器人BB-8", isCollect: false})); console.log(store.getState()); store.dispatch(addToCart({"id": 125, "name": "星战正版机器人BB-10", isCollect: false})); console.log(store.getState());
在这里只是简单介绍了 Redux,至于 Redux 怎么结合 React 使用,怎么处理异步请求等,将在以后再进行总结。
接触Redux会涉及到一些感念,好比纯函数、组合函数、函数柯里化。能够参考文章Functional Programming for JavaScript People。
参考: