每次将 action 发送到 store 时,都会调用每个已注册的 reducer。reducer 只是一个函数,它接受当前状态加上一个动作并返回一个新状态。
所以是的,在引导时会调度一个 init-action(因此每个 reducer 都会被调用)。例如,如果您使用store-devtools,您将看到调用了初始操作@ngrx/store/init
。由于此时当前状态未定义,因此使用以下内容调用 reducer 函数:someReducer(undefined, { type: '@ngrx/store/init' })
当一个函数被一个参数调用undefined
并且它有一个带有默认值的参数时,它将使用该默认值。
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'
这对你来说可能并不新鲜。但希望它有助于回答您关于初始状态的问题:
正如我所说,当前状态是undefined
在调用 init-action 之前。所以当reducer-function有一个带默认值的参数(initialstate)时,store就会用这个初始状态初始化。如果你没有为 reducer 定义一个默认值,那部分状态将保持undefined
. 这可能是一个有效的场景。例如,考虑一个处理管理部分操作的化简器。除非具有提升权限的用户使用您的应用程序,否则您可能不希望在该状态片中有任何内容。
现在到了我认为您的问题来自的地步:
您不想initialState
在默认情况下返回!由于每个 reducer 都会在每个 action-dispatch 上被调用,所以默认情况应该是return state
. 商店不知道一个动作的减速器是什么意思。它用当前状态和分派的动作调用每个reducer,并期望得到一个(新的)状态。
某个 reducer 是否应该对某个动作做出反应取决于您。不应对此操作做出反应的所有其他减速器都应返回其未更改状态(通过 default
案例)。当然,您可以让多个减速器对同一个动作做出反应!
在您的情况下,如果每个减速器initialState
在默认情况下返回,您的整个应用程序状态将重置为其初始状态,但对调度操作做出反应的减速器除外。
TL;DR 对于您的问题:
- 是的,所有 reducer 函数都会在引导程序(以及所有其他动作调度)上调用......
- ...是的,那是商店使用初始状态初始化的时候。
- 不,reducer 不一定总是有初始状态*
- 如果一个状态切片最初是
undefined
,它仍然可以通过reducer 通过返回一个新状态来响应一个动作来改变。
- 每个对动作没有反应的 reducer 都应该通过
default
-case 返回当前状态。
* 当然,这仅在您的应用程序的其余部分能够处理未定义状态时才有意义