Here's the last function, CreateStore. Let's start with a basic usage.
const store = createStore(reducers, state, enhance);This enhance r is apply Middleware (middleware), as you can see. Last article.
Here is the source code. First of all, the logic of the first execution of so many code is very simple. Most of the code defines a function to wait for the call. The real thing is to call a default dispatch method and initialize the current state.
export default function createStore(reducer, preloadedState, enhancer) { if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { //The first step shows that the second parameter can be passed, and if not undefined, the enhancer can be transited to the third parameter. enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { //enhancer must be a function throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) //If you pass enhancer, you pass createStore as a parameter. As I said in my previous article, the third parameter can be passed without, because it will not be received here at all! CreateStore will be executed and returned in applymiddleware. } if (typeof reducer !== 'function') { throw new Error('Expected the reducer to be a function.') } let currentReducer = reducer let currentState = preloadedState //Current state let currentListeners = [] //Current listeners let nextListeners = currentListeners let isDispatching = false //Is it being distributed? function ensureCanMutateNextListeners() { //I can't say why I copied an array shallowly here. If you know it, please help me to answer it. if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() //Just a copy. } } function getState() { //Return to the current state return currentState } function subscribe(listener) { if (typeof listener !== 'function') { //If the listener is a function throw new Error('Expected listener to be a function.') } let isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener) return function unsubscribe() { //Returns a function to deactivate the listener if (!isSubscribed) { return } isSubscribed = false ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) //Remove from listeners } } function dispatch(action) { if (!isPlainObject(action)) { //action must be an object {type:'XXX'} throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } if (typeof action.type === 'undefined') { //Objects must have type attributes (uniquely identifying an action that cannot be repeated) throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } if (isDispatching) { //Two dispatch es cannot be executed simultaneously throw new Error('Reducers may not dispatch actions.') } try { isDispatching = true currentState = currentReducer(currentState, action) //Whether or not the current state is first passed in, the default value is returned based on the first reducer //For example, the first execution of createStore will pass in a type that hardly exists in the case of reducer, so that the default value of the first entry of reducer can be returned. } finally { isDispatching = false //Open the dispatch entrance } const listeners = currentListeners = nextListeners for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() //Execute the listener once } return action } function replaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } currentReducer = nextReducer //Replace the current reducer and execute the default dispatch to return the default value. dispatch({ type: ActionTypes.INIT }) } //Since a regular reducer returns a default value, this step (ActionTypes are rarely defined) is performed to return the default value of reducer. dispatch({ type: ActionTypes.INIT }) return { dispatch, subscribe, getState, replaceReducer } }
Maybe that's the source code. From the last article, we can find that this middleware can be composed, that is to say, it can be combined to achieve the purpose of strengthening dispatch. So what can we do with compose, an applymiddleware?
Promote:
We found that in the createStore we did not say applymiddleware directly, but used the term enhancer, the enhancer.
So I think applymiddleware is actually an enhancer, and that's definitely not the only one. For example:
const store = createStore(combineReducers({ routering: routerReducer }),
{},
composeEnhancers( //This function is also referenced in a class library.
applyMiddleware(myTestMidware_delay, ...middleware,myTestMidware),
myEhancer
)
);
Or the compose routine. The parameter I pass is the createStore function, which returns a createStore function, and then executes the last incoming createStore in the next function. That's what we need to do. The enhancement here is the createStore function.
Because createStore is more than just an executing operation, the return here cannot be omitted. Every time it returns, it is its own enhanced store.const myEhancer = (createstore)=> (reducer, preloadedState) => { const store = createstore(reducer, preloadedState); //Receive the returned store and continue to enhance. const dispatch = (action)=>{ console.log('I am a Enhancer,action For:',action); return store.dispatch(action); } return {...store,dispatch}; }
Enhancer can also enhance dispatch, so it can be achieved through middleware, which can be achieved through enhancer.
Finally, who knows what the ensureCanMutateNextListeners are for, leave a message, thx.