#Understand what middleware is
https://github.com/zp1112/blog/issues/11
thunk Middleware
- Let's see how middleware works.
- index.js
import {Provider} from 'react-redux' import storeData from './reducerfile/index.js' import {createStore, applyMiddleware} from 'redux' import thunk from 'redux-thunk' const store = createStore(storeData, applyMiddleware(thunk)) ReactDOM.render( <Provider store={store}> <App/> </Provider>, document.getElementById('root') )
- action.js
export const fetchData = () => (dispatch) => { dispatch(change(9999, 6666)) setTimeout(() => { getApi().then(data => { console.log(data) dispatch(change(data.age, data.text)) }) },1000) }
Discovery is the action of the original simple object, injected with the rewritten dispatch, and then other operations can be done in this action.
- After redux uses middleware, it rewrites dispatch.
Invoke in component: dispatch(action) = middleware(store)(store.dispatch)(action) / /
- When using applyMiddleware, the implementation rewrites the dispatch code
- The main function of applyMiddleware is to pass it to the middleware store, dispatch, and rewrite dispatch according to different middleware.
export function applyMiddleware(middleware) { // return createStore => (...args) => { const store = createStore(...args) let dispatch = store.dispatch const midApi = { getState: store.getState, dispatch: (...args) => dispatch(...args) // Native dispatch } dispatch = middleware(midApi)(store.dispatch) //Note that when the dispatch is rewritten, the native dispatch is also saved and transferred to the middleware. return { ...store, dispatch //The dispatch here has been rewritten } } }
- Middleware, implementation principle
const thunk =(store) => next => action =>{} // The dispatch taken here is the rewritten dispatch. next is equivalent to the original dispatch. const thunk = ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState) //The dispatch here is equivalent to middle(store)(store.dispatch)(action) } return next(action) //If the return is not a function, it will be directly dispatch ed when there is no middleware. // Note that next here is equivalent to the native store.dispatch }
From the above, we can know that the middleware needs to obtain the store.
So applyMiddleware
function middleware({midApi}){ return function(dispatch){ return function(action){ action(dispatch) } } } function action(dispatch){ dispatch(action) const data = await getData() dispatch({type: 'DO',payload: data}) }
// action is function dispatch(action) // Equivalent to middleware(midApi)(dispathc)(action()) // Execute action(dispatch) //Because dispath has been reassigned when using middleware. export function applyMiddleware(middleware) { // return createStore => (...args) => { // The key step is to get a store object through createStore. // The store object has dispatch and getState methods const store = createStore(...args) let dispatch = store.dispatch const midApi = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // To execute dispatch later is to execute middleware(midApi)(store.dispatch) dispatch = middleware(midApi)(store.dispatch) return { ...store, dispatch } } } thunk(midApi)(dispathc)(action()) // Execute action(dispatch)
Key:
- applyMiddleWare gets the createStore method
- The createStore() execution returns an object containing the dispatch and getState
So dispathc is reassigned to middleware(midApi)(store.dispatch).
dispatch(action) //Equivalent to middleware(midApi)(store.dispatch)(action)
Why can applyMiddleWare call the createStore method and createStore() returns an object? What does the returned object contain?
See the source code of createStore
- Part of the source code of createStore
export default function createStore(reducer, preloadedState, enhancer) { let currentReducer = reducer let currentState = preloadedState / let isDispatching = false // So above export { dispatch, subscribe, getState, replaceReducer, [$$observable]: observable } }
The dispatch and getState methods are exposed in the source code of createStore, so the dispatch and getState can be obtained in applyMiddleware.
Why can I get the createStore method
export default function createStore(reducer, preloadedState, enhancer) { if ( (typeof preloadedState === 'function' && typeof enhancer === 'function') || (typeof enhancer === 'function' && typeof arguments[3] === 'function') ) { throw new Error( 'It looks like you are passing several store enhancers to ' + 'createStore(). This is not supported. Instead, compose them ' + 'together to a single function.' ) } 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.') } // The enhancer here is the apple middleware above // The createStore called by the enhance function is passed in. return enhancer(createStore)(reducer, preloadedState) } ......... }