redux核心思路和代码解析
最近在公司内部培训的时候,发现很多小伙伴只是会用redux、react-redux、redux-thunk的api,对于其中的实现原理和数据真正的流向不是特别的清楚,知其然,也要知其所以然,其实redux的源代码非常简介,下面逐一介绍,
1.先看一个简单的redux应用的例子:
import { createStore, combineReducers } from 'redux';
const year = (state, action) => {
let defaultState = {
year: 2017
}
state = state || defaultState;
switch (action.type) {
case 'add':
return {
year: state.year + 1
};
break;
case 'sub':
return {
year: state.year - 1
};
break;
default:
return state;
break;
}
}
const count = (state, action) => {
let defaultState = {
count: 1
}
state = state || defaultState;
switch (action.type) {
case 'addone':
return {
count: state.count + 1
};
break;
case 'subone':
return {
count: state.count - 1
};
break;
default:
return state;
break;
}
}
const reducer = combineReducers({
year: year,
count: count
})
const store = createStore(reducer);
store.subscribe(() => {
console.log('the year is ' + store.getState().year.year);
});
store.subscribe(() => {
console.log('数字是' + store.getState().count.count);
});
const action1 = {
type: 'add'
}
const action2 = {
type: 'addone'
}
const action3 = {
type: 'hello'
}
store.dispatch(action1);
store.dispatch(action2);
store.dispatch(action3);
上面代码执行后打印出来的结果是:

想必大部分小伙伴都觉得很简单。
export default function createStore(reducer, preloadedState, enhancer) { function getState() {} function subscribe(listener) {} function dispatch(action) {} function replaceReducer(nextReducer) {} ... return { dispatch, subscribe, getState, replaceReducer, ... } }
2.1.1 subscribe方法的核心代码,就是把一个一个的监听函数放入到Listeners的数组,然后返回一个unsubscribe函数,一个闭包函数,包含着传入的listeners函数,执行该函数从监听数组中移除该listeners
function subscribe(listener) { if (typeof listener !== 'function') { throw new Error('Expected listener to be a function.') } let isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener) return function unsubscribe() { if (!isSubscribed) { return } isSubscribed = false ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } }
2.1.2 getState 直接返回当前的state的值,如果没有进行任何操作,直接返回默认值,如果是经过dispatch(action)之后,在dispatch中触发了reducer函数,生成了新的state,也是直接返回
function getState() { return currentState }
2.1.3 dispatch store上的最核心方法, 两部分组成,第一部分直接把当前的state和传入的action直接传入reducer函数,执行,生成新的state,供getState使用,第二部分是直接循环执行subscribe中添加到listeners数组中的监听函数,也就是触发监听函数,
逻辑非常简单。
function dispatch(action) {
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
2.2 combineReducers,将多个reducer合并成一个rootReducer,本质上为合并对象,并返回一个新的总的的reducer函数
function combineReducers(reducers) { const reducerKeys = Object.keys(reducers) const finalReducers = {} for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] if (typeof reducers[key] === 'function') { finalReducers[key] = reducers[key] } } const finalReducerKeys = Object.keys(finalReducers) return function combination(state = {}, action) { let hasChanged = false const nextState = {} for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] const previousStateForKey = state[key] const nextStateForKey = reducer(previousStateForKey, action) if (typeof nextStateForKey === 'undefined') { const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey !== previousStateForKey } return hasChanged ? nextState : state } }
combineReducers的一个简单实现方式,更能明白其中的工作原理:
const combineReducers = (reducers) => { return (state = {}, action) => { return Object.keys(reducers).reduce( (nextState, key) => { nextState[key] = reducers[key]( state[key], action); return nextState; }, {}) } }
2.3 applyMiddleware 中间件,对dispatch的增强,一般为添加异步操作等,例如redux-thunk中间件,实际上就是如果action是个方法,则执行这个方法,如果不是则正常dispatch(action)
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: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
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;
3.react-redux
3.1通过provider 提供store,react通过Context属性,可以将props直接给子孙component,无须通过props层层传递,Provider仅仅起到获得store, 然后将其传递给子孙元素而已
3.2 connect 这个是最关键的方法,


浙公网安备 33010602011771号