接下来我们先什么都不考虑先来实现我们的需求,现在 action 创建函数 asyncChangeAge 因为返回的是一个对象,其 type 值为 undefined 所以当我们点击按钮时 reducer 将会一直匹配到默认情况,返回的将是当前的状态,接下来我们先让我们的 action 创建函数 asyncChangeAge 生效,达到异步修改状态的作用;
扩展 createStore既然 asyncChangeAge 返回的不再是一个 action 对象,而是一个函数;那么其实我们要做的事情是很简单的,我们只需要针对 createStore 中的返回值 dispatch 进行一个简单的扩展即可;通过判断 dispatch 中的 action 参数是否是函数而进行不同的操作:
// redux.js export const createStore = (reducer) => { ...... // 在createStore 我们对返回值 dispatch 进行了封装 const dispatchExtend = (action) => { if(typeof action === 'function'){ // action 为函数,执行函数 action(dispatch, getState); } else { // action 为非函数(对象)调用dispatch dispatch(action); } } return {getState, dispatch: dispatchExtend, subscribe}; }
5.3 抽离封装
上文我们通过对 createStore 的返回值 dispatch 进行了扩展,实现了 redux-react 的异步操作,但问题是我们将代码写死在 createStore 中了,redux-react 的异步操作应该是一个可选项而不应该是必选项;
重新扩展 createStore :新增参数 middleware (函数), 在函数 createStore 开始位置判断 middleware 是否存在,存在则执行;
// redux.js export const createStore = (reducer, middleware) => { // 判断 middleware 是否存在,存在则执行 if(middleware){ return middleware(createStore)(reducer); } let state; const listeners = []; const getState = () => { return state; } const dispatch = (action) => { state = reducer(state, action); listeners.forEach(v => v()); } const subscribe = (listener) => { listeners.push(listener); } dispatch({type: '%$&HJKAJJHDJHJ'}); return {getState, dispatch, subscribe}; }
编写函数 applyMiddleware ,在创建 store 时 作为 createStore 第二参数// App.js const applyMiddleware = (createStore) => (redux)=> { // 在这里进行创建 store const store = createStore(redux); // 返回store return {...store} } const store = createStore(reducer, applyMiddleware);
在 applyMiddleware 函数内扩展 dispatch上文 applyMiddleware 函数并其实没做任何事情, 只是在 createStore 函数外面套了一层函数,那么接下来我们做点正事,来扩展一下我们的 dispatch
// App.js const applyMiddleware = (createStore) => (redux)=> { const store = createStore(redux); const midApi = { getState: store.getState, dispatch: (...args) => {dispatch(...args);} }; const dispatch = (action) => { if( typeof action === 'function' ){ action(midApi.dispatch, midApi.getState); } else { store.dispatch(action); } } return { ...store, dispatch }; }
5.4 扩展分离
上文已经实现了我们想要的效果了,我们在 applyMiddleware 对 dispatch 进行了扩展;然而我们是那么容易满足的嘛,当然不是的!! applyMiddleware 中对 dispatch 的扩展我们还可以将其单独提出来封装成一个函数;
重写 applyMiddleware ,再给 applyMiddleware 包裹一层函数: 将对 dispatch 的扩展抽离,封装成方法;// App.js const applyMiddleware = (middleware) => (createStore) => (redux)=> { const store = createStore(redux); const midApi = { getState: store.getState, dispatch: (...args) => {dispatch(...args);} }; const dispatch = middleware(midApi)(store.dispatch); return { ...store, dispatch }; }
thunk 中间件: 其实 thunk 才是真正的中间件;applyMiddleware 只是用来绑定中间件的// App.js const thunk = ({dispatch, getState}) => next => (action) => { if(typeof action === 'function'){ action(dispatch, getState); } else { next(action); } };
在调用 createStore 时绑定中间件 thunk// App.jsx const store = createStore(reducer, applyMiddleware(thunk));
5.5 代码整理