Redux Source Analysis Series (ii): ' Combinereducer '

Source: Internet
Author: User

In the previous chapter, we explained the CreateStore. Next, let's take a look at combinereducer.
In Redux, we prohibit the creation of more than one store in the application (we are discussing the client application by default, and the homogeneous application does not apply to this rule).

However, as applications become more complex, reducer functions need to be split, and each piece of split is independently responsible for managing part of the state.

Combinereducer is to combine a number of reducer functions as value object, merged into a rootreducer. Then you can call CreateStore on this reducer.

Below, we take a concrete look at the source code:

Import {actiontypes} from './createstore ' import isplainobject from ' lodash/isplainobject ' import warning from './utils/  Warning ' function getundefinedstateerrormessage (key, action) {const ACTIONTYPE = action && Action.type const ActionName = (ActionType && ' "${actiontype.tostring ()}" ") | | ' An action ' return (' Given action ${actionname}, reducer ' ${key} ' returned undefined. ' + ' to ignore a action , you must explicitly return to the previous state. ' + ' If you are want this reducer to hold no value, your can return null instead of undefined. ')} function Getunexpect Edstateshapewarningmessage (InputState, reducers, Action, Unexpectedkeycache) {Const Reducerkeys = Object.keys (
    reducers) Const ARGUMENTNAME = Action && Action.type = = Actiontypes.init? ' preloadedstate argument passed to CreateStore ': ' Previous state received by the Reducer ' if (reducerkeys.length = = = 0) {return (' Store does not have a valid reducer. MakE sure the argument passed ' + ' to Combinereducers are an object whose values are reducers. ' } if (!isplainobject (InputState)) {return (' the ${argumentname} has unexpected type of ' + ({}). Tostring.call (InputState). Match (/\s ([a-z| a-z]+)/) [1] + ' ". Expected argument to be a object with the following ' + ' keys: ' ${reducerkeys.join (' ", ' ')}" ')} const UN Expectedkeys = Object.keys (inputstate). Filter (Key =>!reducers.hasownproperty (key) &&!UNEXPECTEDKEYCAC He[key]) Unexpectedkeys.foreach (key => {Unexpectedkeycache[key] = true}) if (unexpectedkeys.length ; 0) {return (' unexpected ${unexpectedkeys.length > 1? ' Keys ': ' key '} ' + ' ' ${unexpectedkeys.join (' ", ' ')} ' found in ${argumentname}. ' + ' expected to find one of the known reducer keys instead: ' + ' ${reducerkeys.join (' ", ' ')} '. Unexpected keys would be ignored. ')}/** * Traverse reducer in reducers, check reduWhether the CER is a reducer that conforms to the Redux specification.
 * Use Actiontypes.init and random type generated action as the second parameter, check separately * If the state returned is undefined, it does not conform to the Redux specification. * @param {Object} reducers/function Assertreducershape (reducers) {Object.keys (reducers). ForEach (Key => {Co NST reducer = Reducers[key] Const INITIALSTATE = reducer (undefined, {Type:ActionTypes.INIT}) if (typeof Initia
        Lstate = = ' undefined ') {throw new Error (' Reducer ' ${key} "returned undefined during. ') ' If the state passed to the ' reducer be undefined, you are must ' + ' explicitly return of the initial state. The initial state may ' + ' is undefined.

    If you don ' t want to set a value of ' reducer ', ' + ' can use NULL instead of undefined. ')}
    The const TYPE = ' @ @redux/probe_unknown_action_ ' + math.random (). toString. Substring (7). Split ("). Join ('. ') if (typeof reducer (undefined, {type}) = = ' undefined ') {throw new Error (' Reducer ' ${key} ' returned Undefined when probed with a random type. ' + ' Don ' t try to handle ${actiontypes.init} or other actions in ' redux/* ' ' + ' namespace. They are considered private. Instead, you are must return the ' + ' the ' + ' the ' + ' of the ' unknown actions, unless it is undefined, ' + ' in W Hich case your must return to the initial state, regardless of the ' + ' action type. The initial state may is undefined, but can be null. '}})} Export default function Combinereducers (r
  Educers) {///First filter to filter out key value pairs that are not function in 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] = = ' Undefi Ned ') {warning (' No reducer provided for key "${key}" ')} if (typeof reducers[key] = = ' function ' {Finalreducers[key] = Reducers[key]}}//second filter, detecting 'Finalreducers ' redux ' reducer ' const Finalreducerkeys = Object.keys (finalreducers) Let Unexpectedkeycache if (Process.env.NODE_ENV!== ' production ') {Unexpectedkeycache = {}} Let Shapeassertionerror try {Asser Treducershape (Finalreducers)} catch (e) {shapeassertionerror = e} return function combination (state = {}, AC
    tion) {////If the Finalreducers detected an error just now, throw an error. if (shapeassertionerror) {throw Shapeassertionerror}//If not production the environment throws warning if (Process.env.NODE _env!== ' production ') {Const WARNINGMESSAGE = getunexpectedstateshapewarningmessage (state, finalreducers, action,
    Unexpectedkeycache) if (warningmessage) {Warning (warningmessage)}} let Haschanged = False
    Const NEXTSTATE = {}//Traverse all reducer, execute separately, combine the computed state to generate a large state.
    So, any action,redux will traverse all the reducer.
  for (Let i = 0; i < finalreducerkeys.length; i++) {Const KEY = Finalreducerkeys[i]    CONST REDUCER = Finalreducers[key]//computes a state for each reducer. Const PREVIOUSSTATEFORKEY = state[key] Const NEXTSTATEFORKEY = reducer (Previousstateforkey, action)//if the calculated S
      Tate have undefined, throw errors.
        if (typeof Nextstateforkey = = ' undefined ') {Const errormessage = getundefinedstateerrormessage (key, action)
      Throw the new Error (errormessage)}//merges each reducer computed state into a large state.
      Nextstate[key] = nextstateforkey//As long as there is a reducer the computed state is different from the previous one, it indicates that the status tree has changed. haschanged = haschanged | | Nextstateforkey!== Previousstateforkey} return haschanged? Nextstate:state}}

Combinereducer's code is actually very simple. First of all, it will pass two screening, the first filter will reducers value value is not a function of the key-value pairs are removed, the second filter will be reducers in the Redux specification reducer to filter out.

So what is the reducer that conforms to the Redux specification?
Let's take a look at the Assertreducershape function:
Traverse the reducer in reducers to check if Reducer is the reducer that conforms to the Redux specification.
Using the Actiontypes.init and random type generated action as the second parameter, examine each
If the returned state is undefined, the Redux specification is not met.

Next, set a flag called Haschanged, which is false by default. It then iterates through all the reducer in the reducers, computes the reducer, and combines the child state it returns into a large state. Compare the computed child state to the same as the previous child state and, if different, set haschanged to True.
haschanged = haschanged | | Nextstateforkey!== Previousstateforkey
As long as there is a reducer computed state and not the same as before, it indicates that the status tree has changed

Finally, the nextstate or state is returned by determining whether haschanged changes.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.