1. 基本概念
redux有以下几个基本概念:
1.1. action
action: 是一个对象,对一个行为的基本描述
{
type:'add',
todo
}
1.2 action creator
一个函数,返回结果是一个action
function add (todo) {
return {
type: 'add',
todo
}
}
1.3 reducer
真正更新数据操作的函数
let todoReducer = function (state = todoList, action) {
switch (action.type) {
case 'add':
return [...state, action.todo]
case 'delete':
return state.filter(todo => todo.id !== action.id)
default:
return state
}
}
store: 只有一个
dispatch:触发一个action
subscribe : 订阅store
getState :获得当前的state
replaceReducer :更换reducer
observable :
2. createStore源码解析
export default function createStore(reducer, preloadedState, enhancer) {
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
如果 preloadState是函数,并且enhancer为空, enhancer =preloadState
接着,如果有enhancer ,那么 return enhancer(createStore)(reducer, preloadedState)
结合我们的调用分析一下我们通常调用的代码:
let store = createStore(todoReducer, applyMiddleware(thunk,logger))
是怎么来的。
preloadState是函数,并且enhancer为空, enhancer = applyMiddleware(thunk,logger)
return enhancer(createStore)(reducer, preloadedState) = return applyMiddleware(thunk,logger)(createStore)(reducer, preloadedState)
3. applymiddleware 源码解析
中间件是通过next来进入下一个中间件的,执行完毕后,会调用最原始的store.disptach,reducer执行完毕后,该次操作并没有完毕, 还会依次返回到中间件。
任何一个中间件不next ,其后面的中间件都不会执行
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
所有中间件的格式都是第一层参数都是 {disptach,getState}这个样子
({dispatch, getState} ) => next => action => {......}
第二句就是把每个middleware传入参数,初始化一下,这里的最大作用就是利用闭包,让每个middleware拥有同一份disptach和getState的引用。
核心的一句:
dispatch = compose(...chain)(store.dispatch)
这样的函数是整个作为前面一个函数的next参数存在的,所以你每次next(action)实际上就是进入下一个中间件的执行体,
3.1 redux-thunk的解析
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
4. compose源码解析
其作用是把一系列的函数,组装生成一个新的函数,并且从后到前,后面参数的执行结果作为其前一个的参数。
如:
compose(f, g, h) is identical to doing
* (...args) => f(g(h(...args))).
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
把b(...args)作为参数传入a a(b(...args))再执行
我们知道reduce函数返回是一个值。上面函数传入的回调函数是(a, b) => (...args) => a(b(...args))其中a是当前的累积值,b是数组中当前遍历的值。假设调用函数的方式是compose(f,g,h),首先第一次执行回调函数时,a的实参是函数f,b的实参是g,第二次调用的是,a的实参是(...args) => f(g(...args)),b的实参是h,最后函数返回的是(...args) =>x(h(...args)),其中x为(...args) => f(g(...args)),所以我们最后可以推导出运行compose(f,g,h)的结果是(...args) => f(g(h(...args)))。发现了没有,这里其实通过reduce实现了reduceRight的从右到左遍历的功能,但是却使得代码相对较难理解。在Redux 1.0.1版本中compose的实现如下:
export default function compose(...funcs) {
return funcs.reduceRight((composed, f) => f(composed));
}
5. bindActionCreator源码解析
bindActionCreators:对disptach的一种封装,可以直接执行或者通过属性方法的调用隐式的调用dispatch,而不用显式调用dispacth
例子:
// action creater
let actionCreaters = {
add: function (todo) { //添加
return {
type: 'add',
todo
}
}, delete: function (id) {
return {
type: 'delete',
id
}
}
}
let boundActions = bindActionCreators(actionCreaters, store.dispatch)
boundActions.add({
id: 12,
content: '睡觉觉'
})
let boundAdd = bindActionCreators(actionCreaters.add, store.dispatch)
boundAdd({
id: 13,
content: '陪媳妇'
})
源码:
export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(
`bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` +
`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
)
}
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
bindActionCreators.js 里面有一个 bindActionCreator,bindActionCreators 方法,
bindActionCreators会根据传入的是函数还是对象,采取不同的处理方式,
入参是函数,返回函数; 传入对象,返回对象。
6. combineReducers源码解析
combineReducers:把recuder函数们,合并成一个新的reducer函数,dispatch的时候,挨个执行每个reducer
在 reducer 层级的任何一级都可以调用 combineReducers。并不是一定要在最外层。实际上,你可以把一些复杂的子 reducer 拆分成单独的孙子级 reducer,甚至更多层。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。