NgRx - How are states combined and initialized

南笙酒味 提交于 2019-12-06 08:04:38

Every time an action is dispatched to the store, every registered reducer is called. A reducer is just a function that takes the current state plus an action and returns a new state.

So yes, on bootstrap an init-action is dispatched (and therefore every reducer is called). If you use store-devtools for example, you will see that the initial action is called @ngrx/store/init. Since the current state is undefined at this point, the reducer-function is called with the following: someReducer(undefined, { type: '@ngrx/store/init' })

When a function gets called with a parameter that is undefined and it has a parameter with a default value, it will use that default value instead.

function funcWithoutDefault(myParam) {
    console.log(myParam);
}

funcWithoutDefault('hello'); // 'hello'
funcWithoutDefault(undefined); // undefined

function funcWithDefault(myParam = 'world') {
    console.log(myParam);
}

funcWithDefault('hello'); // 'hello'
funcWithDefault(undefined); // 'world'

That's probably nothing new to you. But hopefully it helps to answer your question about initial state:

As I said, the current state is undefined before the init-action is called. So when the reducer-function has a parameter with a default value (the initialstate), the store will be initialized with this initial state. If you don't define a default value for a reducer, that slice of the state stays undefined. This could be a valid scenario. Consider for example a reducer that handles actions for an admin-section. Unless a user with elevated rights uses your application, you might not want to have anything in that state-slice.

Now to the point where I presume your question came from:

You don't want to return the initialState in the default case! Since every reducer gets called on every action-dispatch, the default case should return state. The store doesn't know what reducer an action is meant for. It calls every reducer with the current state and the dispatched action and expects to get a (new) state back.
If a certain reducer should react to an action is up to you. Every other reducer that should not react to this action should return it's unaltered state (via the default case). And of course you can have multiple reducers react to the same action!

In your case, if every reducer returns initialState in the default case your whole app-state would reset to it's inital state, except for the reducer that reacts to the dispatched action.

TL;DR for your questions:

  • Yes, all reducer-functions get called on bootstrap (and on every other action dispatch)...
  • ... and yes, that is when the store gets initialized with the initial state.
  • No, a reducer must not always have an initial state*
  • If a slice of state is initially undefined, it can still be changed by the reducer reacting to an action by returning a new state.
  • Every reducer not reacting to an action should return the current state via the default-case.

* of course this only makes sense when the rest of your application is able to handle an undefined state

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!