1、redux
抛开react,如果只是仅仅使用redux,就像如下示例:
const initialState = {
name: 'Jack',
age: 27,
gender: 'boy'
};
function reducer(state = initialState, action) {
switch(action.type) {
case 'add':
return { ...state, age: state.age + 1 };
default:
return state;
}
}
const store = createStore(reducer);
store.subscribe(function() {
console.log(store.getState());
});
store.dispatch({ type: 'add' });
这里其实就是一个createStore函数,返回了dispatch、subscribe、getState这三个方法,如下就是redux的简单实现:
function createStore(reducer, enhancer) {
// createStore(reducer, applyMiddleware(thunk));
if (enhancer) {
return enhancer(createStore)(reducer);
}
let state;
let listeners = [];
function subscribe(fn) {
fn && listeners.push(fn);
}
function dispatch(action) {
state = reducer(state, action);
listeners.forEach(lis => lis());
return action;
}
function getState() {
return state;
}
// 用于初始化state,其中type任意名称
dispatch({ type: '@Init_XXX_dXXxx' });
return {
subscribe,
dispatch,
getState
};
}
2、redux实现异步action
正常要想实现异步action,需要引入thunk,如:
import thunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducer';
const store = createStore(reducers, applyMiddleware(thunk));
其中通过applyMiddleware来合并各种thunk。先让我们来看看一个thunk的基本结构:
const thunk = ({ getState, dispatch }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
export default thunk;
这是一个三层嵌套函数,通过next串联各个thunk。
让我们再来看看applyMiddleware的实现:
function applyMiddleware(...middlewares) {
return (createStore) => (...args) => {
const store = createStore(...args);
let dispatch = store.dispatch;
const midApi = {
getState: store.getState,
// 这里保证dispatch是下面compose后,最终生成的dispatch
dispatch: (...args) => dispatch(...args)
};
let midwaresChain = middlewares.map(mw => mw(midApi));
dispatch = compose(...midwaresChain)(store.dispatch);
return {
...store,
dispatch
};
};
}
// fn1(fn2(fn3(...args)))
function compose(...middlewares) {
if (!middlewares) {
return arg => arg
}
return middlewares.reduce((ret, func) => {
return (...args) => ret(func(...args))
});
}
首先对每个thunk传入midApi进行调用,这里midApi对应thunk的第一个参数({ getState, dispatch }),最后形成的数组里的每项都各自对getState和dispatch形成一个闭包。注意:这里的dispatch就是最终compose完成后的dispatch
let midwaresChain = middlewares.map(mw => mw(midApi));
然后对midwaresChain调用compose函数,最后返回的函数为类似这种结构:fn1(fn2(fn3(...args))),然后后再传入store.dispatch调用它。这里store.dispatch对应thunk的第二个参数next,此时每个thunk返回的内容为如下函数。
根据fn1(fn2(fn3(...args)))这个调用顺序,及最后一个fn3这个thunk返回的函数会作为前一个fn2的next入参。
这样调用完成后,会最终返回一个如下函数:
action => {
if (xxx) {
dispatch(xxx);
return;
}
// 这里的next就是后一个thunk返回的action => {}这个函数
return next(action);
};
到此,给redux加入thunk已经实现,这里的thunk可以具备各种功能,如异步thunk:
const thunk = ({ getState, dispatch }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
然后只需要在页面调用时传入thunk:
const store = createStore(reducer, applyMiddleware(thunk));
3、combineReducers
有时我们项目比较大时,会将reducer分为多个文件编写,最后通过combineReducers组合多个reducer。下面是一个使用示例:
import user from './reducer/user.js';
import order from './reducer/order.js';
const reducer = combineReducers({
user,
order,
});
const store = createStore(reducer);
后代组件通过state.user或者state.order来获取对应大状态值。
接着让我们看下combineReducers长什么样子:
export function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers);
const finalReducers = {};
reducerKeys.forEach(key => {
// 过滤不是function的reducer
if (typeof reducerKeys[key] === 'function') {
finalReducers[key] = reducerKeys[key];
}
});
// 过滤后最终的finalReducers
const finalReducerKeys = Object.keys(finalReducers);
// 最终返回的reducer
return (state, action) => {
let hasChanged = false;
const nextState = {};
for (let i = 0; i < finalReducerKeys.length; i++) {
let key = finalReducerKeys[i];
let reducer = finalReducers[key];
let prevStateForKey = state[key];
// 对每一个reducer都执行action,并比较state是否changed
let nextStateForKey = reducer(prevState, action);
if (typeof nextStateForKey === 'undefined') {
throw new Error(`reducer "${key}" returned undefined`);
}
nextState[key] = nextStateForKey;
hasChanged = hasChanged || prevStateForKey !== nextStateForKey;
}
hasChanged =
hasChanged || finalReducerKeys.length !== Object.keys(state).length;
return hasChanged ? nextState : state;
};
}
小结
这片文章对redux中几个常用的函数进行简单的讲解,源代码中会比这篇文章的代码多很多情况的处理。
希望这篇文章对你有所帮助