Source summary read redux

Introduction redux

redux give us expose these methods

{
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose
}

We turn to introduce

createStore

Creating a store of wording:

let store = createStore(reducer, preloadedState, enhancer);

The three parameters reducer createStore, preloadedState, enhancer, the latter two parameters are optional,
when we pass two parameters only, and the second argument is the function, for example:

let store = createStore(reducer, enhancer);

By reading this source

if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

We know that the above createStore be rewritten as:

createStore(educer, undefined, enhancer)

And then by reading the source code this:

if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
  }

Will find that the call has changed the way once again, it becomes less this way

enhancer(createStore)(reducer, undefined)

Examples of a method createStore Therefore, two of the following are equivalent:

第一种
const store = createStore(reducers, applyMiddleware(routeMiddleware, sagaMiddleware, postRedirectMiddleware, pageSizeMiddleware));


第二种
const store = applyMiddleware(routeMiddleware, sagaMiddleware, postRedirectMiddleware, pageSizeMiddleware)(createStore)(reducers);

Finally, store the returned object provides several methods for our use

dispatch,
subscribe,
getState,
replaceReducer,

getState used to obtain currentState, that is, the total value of state

subscribe to register multiple listener functions that will be executed when developers turn to call dispatch

dispatch of the argument is an object action, will be directly executed reducer (action) method, and batch execution contents subscribe listening, after the dispatch will return to perform an action

replaceReducer replace the current reducer, this method can be utilized in a single application using asynchronous, for example, we do not want all the one-time initialization reducer to createStore, but when an asynchronous fetch a page, then reducer of this page before plus old reducer, to back into the latest by replaceReducer method. The advantage of this is that, devtools in the redux tool does not show so much information, it will only show information pages visited, more conducive to our development, of course, due to reduced reducer, the volume of the store will also be less, page run faster.

combineReducers

Source

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers)
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]

    if (process.env.NODE_ENV !== 'production') {
      if (typeof reducers[key] === 'undefined') {
        warning(`No reducer provided for key "${key}"`)
      }
    }

    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }
  const finalReducerKeys = Object.keys(finalReducers)

  let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }

  let shapeAssertionError
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }

  return function combination(state = {}, action) {
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(
        state,
        finalReducers,
        action,
        unexpectedKeyCache
      )
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    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
  }
}

Normally we would use this

combineReducers({
    a:reducer1,
    b:reducer2
})

reducer1 is a function, and any natural combineReducers return is a function, but the reducer are each traversed again, and finally returned data structure

{
    a:state1,
    b:state2
}

And if we put a with b replaced with a unique path path, the path with the project file for each page of the corresponding folder, for example:

combineReducers({
    'component/page1/info/':reducer1,
    'component/page2/user/':reducer2
})

In the time of this data fetch state to take
state [ 'component / page1 / info /'] is not a file can be achieved through a modular folder path, of course we are still a small step away from the modular, that is no manual to write path path, but to build tools (webpack the loader) to traverse completed.

compose

Source

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

Personal feel compose (a, b, c) (d) after the code is a (b (c (d))), any then returned after compose is a function that can accept parameters, compose in code described later in It involved.

applyMiddleware

Source

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

Method of creating a store of:


let store = applyMiddleware(middleware1,middleware2,middleware3)(createStore)(reducers)

Middleware middleware1 code

function middleware1({ getState }) {
  return (next) => (action) => {
    console.log('will dispatch', action)
    let returnValue = next(action)
    console.log('state after dispatch', getState())
    return returnValue
  }
}

applyMiddleware passed in parameter is a plurality of intermediate, intermediate acting reducers is performed before the Switch, the first execution code middleware.

In terms of the parameters corresponding to the source code, then
examples of parameters middleware1, middleware2 equivalent source into a reference ... middlewares,
examples of the parameters corresponding to createstore source into reference createstore,
examples of the parameter reducers corresponding source into a reference ... args.

Source of

const store = createStore(...args)

Get the object store for later use, middlewareAPI Lane getState store objects in the correspond getState, getState () method to obtain currentState, i.e. the total data redux object tree.

chain = middlewares.map(middleware => middleware(middlewareAPI))

middlewareAPI getState this method provides for obtaining intermediate currenState, the array chain acquired this time is a function of the function return value.

This line of code more exciting

dispatch = compose(...chain)(store.dispatch)

First store.dispatch most primitive method as the reference,

dispatch(action)

就相当于
compose(...chain)(store.dispatch)(action),

同时也相当于
middleware1(middleware2(middleware3((store.dispatch))))(action),

Of course, here it is middleware1 has only three layers instead of the original function in the body of the function package closed.

最先执行的是middleware1,
返回了next(action),

也就相当于
middleware2(middleware3((store.dispatch)))(action),

执行完后返回next(action)
就相当于middleware3((store.dispatch))(action),

执行完后返回next(action)
就相当于store.dispatch(action)

We have figured out the whole process, the implementation process applyMiddleware middleware is to keep the next (action),
but only the last is executed next dispatch, before the next transfer represent other middleware, dispatch method only in the last intermediate in the implementation of a piece.

Personally I think this place combines written after compose more exciting, and the design is very clever.

Guess you like

Origin www.cnblogs.com/homehtml/p/12055391.html