Redux 应用程序中的初始状态可以通过两种方式设置:
createStore
( docs link ) 如果您将初始状态传递给您的商店,您如何从商店中读取该状态并将其作为 reducer 中的第一个参数?
最佳答案
TL;DR
Without
combineReducers()
or similar manual code,initialState
always wins overstate = ...
in the reducer because thestate
passed to the reducer isinitialState
and is notundefined
, so the ES6 argument syntax doesn't get applied in this case.With
combineReducers()
the behavior is more nuanced. Those reducers whose state is specified ininitialState
will receive thatstate
. Other reducers will receiveundefined
and because of that will fall back to thestate = ...
default argument they specify.In general,
initialState
wins over the state specified by the reducer. This lets reducers specify initial data that makes sense to them as default arguments, but also allows loading existing data (fully or partially) when you're hydrating the store from some persistent storage or the server.
首先让我们考虑一个只有一个 reducer 的情况。
说你不使用
combineReducers()
.然后你的 reducer 可能看起来像这样:
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
现在假设您用它创建了一个商店。import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState()); // 0
初始状态为零。为什么?因为 createStore
的第二个参数是 undefined
.这是state
第一次传递给你的 reducer 。当 Redux 初始化时,它会分派(dispatch)一个“虚拟” Action 来填充状态。所以你的counter
使用 state
调用 reducer 等于 undefined
. 这正是“激活”默认参数的情况。 因此,state
现在是 0
根据默认 state
值(state = 0
)。将返回此状态 (0
)。让我们考虑一个不同的场景:
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState()); // 42
为什么是42
, 而不是 0
, 这次?因为createStore
被调用 42
作为第二个论点。该参数变为 state
与虚拟 Action 一起传递给您的 reducer 。 这一次,state
不是未定义的(它是 42
!),因此 ES6 默认参数语法无效。 state
是 42
, 和 42
从 reducer 返回。现在让我们考虑一个使用
combineReducers()
的情况。 .你有两个 reducer :
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
combineReducers({ a, b })
生成的reducer看起来像这样:// const combined = combineReducers({ a, b })
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
如果我们调用 createStore
没有 initialState
,它将初始化 state
至{}
.因此,state.a
和 state.b
将是 undefined
当它调用 a
时和 b
reducer 。 两个a
和 b
reducer 将收到 undefined
作为他们的state
参数,如果他们指定默认 state
值,那些将被返回。 这就是组合 reducer 返回 { a: 'lol', b: 'wat' }
的方式。第一次调用时的状态对象。import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState()); // { a: 'lol', b: 'wat' }
让我们考虑一个不同的场景:import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState()); // { a: 'horse', b: 'wat' }
现在我指定了 initialState
作为 createStore()
的参数.从组合 reducer 返回的状态结合了我为 a
指定的初始状态带 'wat'
的 reducer 默认参数指定 b
reducer 选择了自己。让我们回顾一下组合 reducer 的作用:
// const combined = combineReducers({ a, b })
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
在这种情况下,state
已指定,因此它不会回退到 {}
.它是一个带有 a
的对象字段等于 'horse'
,但没有 b
field 。这就是为什么 a
收到 reducer 'horse'
作为它的state
并高兴地退回了它,但是 b
收到 reducer undefined
作为它的state
并因此返回了默认 state
的想法(在我们的示例中,'wat'
)。这就是我们得到 { a: 'horse', b: 'wat' }
的方式作为返回。综上所述,如果你坚持 Redux 约定并在使用
undefined
调用 reducer 时从 reducer 返回初始状态。作为 state
参数(实现这一点的最简单方法是指定 state
ES6 默认参数值),您将对组合 reducer 有一个很好的有用行为。 他们会更喜欢 initialState
中的相应值。传递给 createStore()
的对象函数,但是如果你没有传递任何,或者没有设置对应的字段,默认state
而是选择由 reducer 指定的参数。 这种方法效果很好,因为它提供了现有数据的初始化和水合,但是如果他们的数据没有被保留,它会让单个 reducer 重置他们的状态。当然,您可以递归地应用此模式,因为您可以使用 combineReducers()
在许多层面上,甚至通过调用 reducer 并为它们提供状态树的相关部分来手动组合 reducer。
关于javascript - 在 Redux Reducer 中读取 Store 的初始状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33749759/