在 Redux Reducer 中读取 Store 的初始状态
TL; 博士
没有
combineReducers()
或类似的手动代码,initialState
总是state = ...
在减速器中获胜,因为state
传递给减速器的是initialState
和不是undefined
,所以在这种情况下 ES6 参数语法不会被应用。与
combineReducers()
行为更微妙。状态在 中指定的那些减速器initialState
将收到那个state
。其他减速器将接收undefined
,因此将回退到state = ...
它们指定的默认参数。一般情况下,
initialState
胜过减速器指定的状态。这让化简器可以将对其有意义的初始数据指定为默认参数,而且还允许在您从某些持久性存储或服务器中加载存储时(全部或部分)加载现有数据。
首先让我们考虑一个只有一个减速器的情况。
说你不使用combineReducers()
.
那么您的减速器可能如下所示:
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
第一次传递给您的减速器。当 Redux 初始化时,它会调度一个“虚拟”动作来填充状态。所以你的counter
减速器被调用state
等于undefined
. 这正是“激活”默认参数的情况。因此,state
现在0
按照默认state
值 ( state = 0
)。0
将返回此状态 ( )。
让我们考虑一个不同的场景:
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState()); // 42
为什么这次是42
,而不是0
?因为createStore
被称为 with42
作为第二个参数。这个参数state
与虚拟操作一起传递给你的减速器。这一次,state
不是未定义的(它是42
!),因此 ES6 默认参数语法不起作用。的state
是42
,和42
从减速机返回。
现在让我们考虑一个使用combineReducers()
.
你有两个减速器:
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
生成的减速器combineReducers({ a, b })
如下所示:
// 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
减速器的时间。双方a
和b
减速会收到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()
。从组合减速器返回的状态将我为a
减速器指定的初始状态与'wat'
指定b
减速器自己选择的默认参数相结合。
让我们回忆一下组合式减速器的作用:
// const combined = combineReducers({ a, b })
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
在这种情况下,state
已指定,因此它不会回退到{}
. 它是一个a
字段等于的对象'horse'
,但没有b
字段。这就是为什么a
reducer 接收'horse'
它state
并很高兴地返回它,但b
reducer 接收undefined
它state
并因此返回它的默认想法state
(在我们的例子中,'wat'
)。这就是我们获得{ a: 'horse', b: 'wat' }
回报的方式。
总而言之,如果您坚持 Redux 约定并在它们undefined
作为state
参数调用时从 reducer 返回初始状态(实现这一点的最简单方法是指定state
ES6 默认参数值),您将有组合减速器的一个很好的有用行为。他们会更喜欢initialState
你传递给createStore()
函数的对象中的相应值,但如果你没有传递任何值,或者如果相应的字段没有设置,state
则选择由 reducer 指定的默认参数。这种方法很有效,因为它提供了现有数据的初始化和水化,但是如果它们的数据没有被保留,它会让各个减速器重置它们的状态。当然,您可以递归地应用此模式,因为您可以combineReducers()
在许多级别上使用,甚至可以通过调用减速器并为它们提供状态树的相关部分来手动组合减速器。
简而言之:Redux 是将初始状态传递给 reducer 的人,你不需要做任何事情。
当您调用时,createStore(reducer, [initialState])
您是在让 Redux 知道当第一个动作进入时要传递给减速器的初始状态是什么。
您提到的第二个选项仅适用于您在创建商店时未传递初始状态的情况。IE
function todoApp(state = initialState, action)
只有在 Redux 没有传递状态时才会初始化状态
你如何从 store 中读取 state 并将它作为你的 reducer 中的第一个参数?
combineReducers() 为您完成这项工作。第一种编写方法并不是很有帮助:
const rootReducer = combineReducers({ todos, users })
但另一个等价的更清楚:
function rootReducer(state, action) {
todos: todos(state.todos, action),
users: users(state.users, action)
}
我希望这能回答您的请求(我理解为在传递 intialState 并返回该状态时初始化减速器)
我们就是这样做的(警告:从 Typescript 代码中复制)。
它的要点是if(!state)
mainReducer(factory) 函数中的测试
function getInitialState(): MainState {
return {
prop1: 'value1',
prop1: 'value2',
...
}
}
const reducer = combineReducers(
{
main: mainReducer( getInitialState() ),
...
}
)
const mainReducer = ( initialState: MainState ): Reducer => {
return ( state: MainState, action: Action ): MainState => {
if ( !state ) {
return initialState
}
console.log( 'Main reducer action: ', action )
switch ( action.type ) {
....
}
}
}