最近在这段时间了解了下redux,下面简单记录下所得。html
首先,仍是用几句话简单归纳下redux吧,欢迎拍砖。node
下面,先经过经典应用todos简单介绍下redux的一些基础概念react
state树中存放一个应用程序内全部共享的数据,一个应用程序有且只有一个state。
todos的state结构为git
{ todos: [], // 完整的任务列表 filter: 'SHOW_ALL' // 当前选中的任务过滤条件 }
action是惟一种改变state的方式,用来通知reducers修改state。
action是JavaScript plain object,描述“发生了什么”。
默认action对象内部必须有type字段(字符串)来表示将要执行的动做。github
const ADD_TODO = 'ADD_TODO' { type: ADD_TODO, title: '你个标题党' }
actionCreator就是生成action对象的函数,很是纯的纯函数。编程
function addTodo(title) { return { type: ADD_TODO, title } }
action对象负责描述”发生了什么“,那reducer就是执行者,按照action对象的描述,
严格更新state。
reducer也是一种纯函数,接受action对象和state树做为参数,生成新的state。redux
const reducer = (prevState, action) => nextState
这里reducer采用纯函数的意义是保证应用状态的可预测性,只要传入参数可知,那结果就可知。
同时nextState并非直接修改prevState所得,而是在prevState基础上返回的一个新数组,经过
Object.assign或者immutable.js生成。这样的目的是方便跟踪全局应用状态和回退/撤销操做,
并且能够在React组件内直接经过shouldComponentUpdate(nextProps, nextState)
进行对比。
因此,千万不要“玷污”reducer函数:api
最后,随着应用的复杂,state树也会更加庞大,reducer内部的处理逻辑也会更加复杂。很难想象一堆代
码根据action.type的可能值进行判断处理。
咱们能够经过分解、细化reducers来拆分数据处理逻辑,最后经过redux提供的combineReducers()
API来生成惟一的rootReducer。数组
const todoApp = combineReducers({ visibilityFilter, todos })
store就是将action和reducer联系在一块儿的对象。babel
const = createStore(reducer, initState)
store对象有三种方法,经过这三种方法来维持应用的state。
至此,redux的核心方面已经说完。你可能发现这个redux彷佛和观察者模式差很少呢。其实,它就是一个观察者模式。
咱们能够经过babel-node执行咱们的todos查看redux应用的调用过程。
ps: balel-node是node中安装babel插件转换ES6代码,此时node v6.3.1还不支持export & import用法
上面redux调用流程图:
redux只是一种应用状态管理器,咱们须要经过react-redux结合React一块儿使用才能开发出完整的应用。
react-redux是redux官方提供的一种绑定react的实现方案。主要提供了两个api:
<Provider store>
包裹React顶层组件,而且为子组件传递Redux store propsconnect([mapStateToProps], [mapDispatchToProps])
connect方法主要有可选参数,具体可参考官网API文档,不过日常主要使用这两个
{ addTodo, removeTodo, }
react组件内部经过this.props.addTodo('hello')
调用。
在介绍接下来的内容以前,插个已经被问烂的问题:什么是js闭包和函数柯里化。此处只是简单的举个例子说明一下
let test = (a, b) => a + b let curryTest = a => b => a + b
好,接下来继续扯咱们的,什么是Middleware
此处,Redux经过Middleware实现对store.dispatch的封装,扩展
该函数原有的功能,典型的是实现state日志记录的功能。
// 手动记录logger功能代码 console.log('dispatching', action) store.dispatch(action) console.log('next state', store.getState())
而redux经过Middleware创建一个store.dispatch的链条,每层middleware都会接受前一个middleware返回
的next(最初是store.dispatch), 而后在进行封装,返回给后一个middleware调用的next,直到最后一个middleware返回
原始的store.dispatch处理action对象。
例如官网的logger middleware代码:
const logger = store => next => action => { console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result }
applyMiddleware(...middlewares)源码:
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, initialState, enhancer) => { var store = createStore(reducer, initialState, enhancer) var dispatch = store.dispatch var chain = [] var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
compose(..funcs)源码
export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } else { const last = funcs[funcs.length - 1] const rest = funcs.slice(0, -1) return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args)) } }
经过源码咱们能发现,applyMiddleware接受的Middlewares数组除了最后一个middleware接受原始的store.dispatch(Array.prototype.reduceRight),其他middleware都会接受前一个middleware封装后的next,因此此时的redux流程图就是下面这样:
介绍完redux的middleware,那redux的异步流程模式也就出来了。官网是经过redux-thunk Middleware实现的,咱们看下thunkMiddleware的源码:
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; }
这样store.dispatch就能够接受函数,也就能够将其和网络请求状态动态绑定在一块儿了。
具体源码可参考官网async示例源码。
本文参考连接: