Redux是一个程序架构,源于Flux(Facebook提出的一种架构),然而,它不只能够应用于React,还能够应用于其余任何框架中。值得一提的是,Redux的源代码不多,可是他的逻辑拆分和函数式编程的设计思想是很是值得学习的。html
当一个JavaScript单页应用变得愈来愈复杂时,咱们要处理的数据(model)也变得愈来愈庞大,随之而来的是每一个数据的状态(state)会变得难以维护。当一个model改变时,咱们可能要手动处理由此引起的其余model的变化,更糟糕的是,其余model变化可能又会引发另外一些model的变化,这样产生连锁反应。最后咱们很容易就会不记得model在何时以及如何发生改变。这正是Redux能够解决的最大痛点之一—以统一的方式管理数据状态。
统一的数据状态管理体现为如下2个方面:react
惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。编程
Actionredux
Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的惟一来源。直白的说,action就是一种消息类型,他告诉Redux是时候该作什么了,并带着相应的数据传到Redux内部(即接下来介绍的Reducer)。
Action就是一个简单的对象,其中必需要有一个type属性,用来标志动做类型(reducer以此判断要执行的逻辑),其余属性用户能够自定义,但要尽可能简单。如:segmentfault
{type: SET_ALL,index: 5}
Action Creator
Action Creator是一个用来自动生成Action的函数,这也是Redux函数式编程的一种体现。一般,咱们会按照业务逻辑或组件把相关的Action Creator放在一个文件中,形式以下:架构
export const SHOW_SLIDER = 'SHOW_SLIDER'; export const RIGHT_SLIDER = 'RIGHT_SLIDER'; export const showSliderAction = (index) => { return { type: SHOW_SLIDER, index }; } export const rightSliderAction = (length) => { return { type: RIGHT_SLIDER, length }; }
其中showSliderAction和rightSliderAction就是Action Creator。
因为Action Creator的形式大致相同,咱们还能够建立一个用来生成Action Creator的函数以进一步简化。并发
export const makeCreateAction = (type, ...keys) => { return (...data) => { let action = {type}; keys.forEach((v,i) => action[v] = data[i]); return action; } } export const showSliderAction = makeCreateAction(SHOW_SLIDER, index); export const rightSliderAction = makeCreateAction(RIGHT_SLIDER, length);
Reducer
Reducer 指定了应用状态的变化如何响应 actions 并发送到 store 的,action只是告诉Redux该干什么了,并无告诉他怎么干,而reducer就是根据action处理state如何改变的逻辑。
Reducer必须是一个纯函数(缘由稍后解释),他根据action处理state的更新,若是没有更新或遇到未知action,则返回旧state;不然返回一个新state对象。注意:不能修改旧state,必须先拷贝一份state,再进行修改,也可使用Object.assign函数生成新的state。另外,state参数需先进行初始化。实例代码以下:框架
//初始状态 let initialState = {hiddenClass: 'g-hidden',currentIndex:0}; let sliderReducer = function (state = initialState, action) { switch(action.type){ case sliderAction.SHOW_SLIDER: return {hiddenClass: '',currentIndex:action.index}; case sliderAction.RIGHT_SLIDER: if(state.currentIndex == action.length-1){ return Object.assign({}, state, {currentIndex:0}); }else{ return Object.assign({}, state, {currentIndex:Number.parseInt(state.currentIndex)+1}); } default: return state; } } export default sliderReducer;
使用纯函数的缘由:异步
首先,纯函数的特色是: •函数的返回结果只依赖于它的参数。 •函数执行过程里面没有反作用。(不会对外界产生影响)
若是不使用纯函数,即直接更改state值会怎么样呢?ide
… … case sliderAction.RIGHT_SLIDER: if(state.currentIndex == action.length-1){ state.currentIndex = 0; return state; } … …
以后会发现,不管state如何变化,UI都不会更新。如下是Redux的部分源码:
经过查看Redux源码得知,新旧state的比较只是对引用地址的比较,若是reducer只是返回旧state(即previousStateForKey)的更新,新state(nextStateForKey)实际上和旧state引用的都是同一块内存地址,因此不管如何更改,新旧state始终保持相同。这就是为何reducer必须是纯函数的缘由。
Reducer拆分与合并:
Reducer 函数负责生成 State。因为整个应用只有一个 State 对象,包含全部数据,对于大型应用来讲,这个 State 必然十分庞大,致使 Reducer 函数也十分庞大。因此须要先对reducer进行拆分,拆分的原则能够按业务逻辑进行划分,若是是react的话,能够直接和react的组件相对应进行划分。
划分好以后,能够用Redux提供的combineReducers方法进行合并,十分方便。
import { combineReducers } from 'redux'; import photomainReducer from './photomainReducer'; import sortReducer from './sortReducer'; import sliderReducer from './photoSliderReducer'; export default combineReducers({ photomainReducer, sortReducer, sliderReducer });
Store
Store 是把Action、Reducer联系到一块儿的对象。Store 有如下职责:
1.维持应用的 state; 2.提供 getState() 方法获取 state; 3.提供 dispatch(action) 方法更新 state; 4.经过 subscribe(listener) 注册监听器; 5.经过 subscribe(listener) 返回的函数注销监听器。
(1) 建立store
Redux应用应该只有一个store,他提供了建立store的API—createStore(reducer, initState)。第一个参数为一个reducer,能够接受经过combineReducers合并后的reducer,第二个是可选参数,意思是能够设置应用的初始state。
const store = createStore( indexPhotomainReducer, ); export default store;
(2)State
应用的state也应该只有一个,里面包含了全部的应用数据。当须要获取state的时候,须要使用store.getState()方法。
(3)store.dispatch(action)
UI更新state 的惟一途径,经过dispatch方法发起action,唤起对应的reducer更新state。
(4)store. subscribe(listener)
经过此方法能够设置监听函数,一旦state发生变化,就会当即调用监听函数(listener)。同时,subscribe的返回值(其实是一个unsubscribe函数)能够解除监听。如:
// 每次 state 更新时,打印日志 // 注意 subscribe() 返回一个函数用来注销监听器 const unsubscribe = store.subscribe(() => console.log(store.getState()) ) // 中止监听 state 更新 unsubscribe();
(1)首先,用户发出 Action(如click事件)。
store.dispatch(SHOW_SLIDER)
(2) Store 自动调用 Reducer,而且传入两个参数:当前 State 和收到的 Action。 Reducer根据Action的type调用相应的分支, 返回新的 State 。
let initialState = {hiddenClass: 'g-hidden',currentIndex:0}; let sliderReducer = function (state = initialState, action) { switch(action.type){ case sliderAction.SHOW_SLIDER: return {hiddenClass: '',currentIndex:action.index}; default: return state; } }
(3) State 一旦有变化,Store 就会调用监听函数。
store.subscribe(listener);
(4) listener能够经过store.getState()获得当前状态。若是使用的是 React,这时能够触发从新渲染 View。
function listerner() { let newState = store.getState(); component.setState(newState); }
以上为Redux的数据流动过程。
本篇到此告一段落,下一篇介绍Redux的异步实现。