[英]Read Store's Initial State in Redux Reducer
TL; DR
如果没有
combineReducers()
或类似的手动代码,initialState
总是战胜state = ...
在减速,因为state
传递到减速机是initialState
, 而不是undefined
,所以ES6参数语法不会在这种情况下得到应用。使用
combineReducers()
,行为更加微妙。 那些在initialState
指定状态的reducer将接收该state
。 其他reducers将收到undefined
,因此会回退到他们指定的state = ...
default参数。通常,
initialState
胜过reducer指定的状态。 这使得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
传递给你减速的第一次。 当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
? 因为使用42
作为第二个参数调用createStore
。 此参数将成为与reduction一起传递给reducer的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 })
生成的combineReducers({ a, b })
如下所示:
// const combined = combineReducers({ a, b })
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
如果我们在没有initialState
情况下调用createStore
,它将把state
初始化为{}
。 因此, state.a
和state.b
将在调用a
和b
reducers时被undefined
。 a
和b
reducers都将接收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
减速收到'horse'
作为其state
,并愉快地回到住处,但b
收到减速undefined
其state
,从而恢复其默认的思想 state
(在本例中, 'wat'
)。 这就是我们获得{ a: 'horse', b: 'wat' }
作为回报的方式。
总而言之,如果你坚持使用Redux约定并在使用undefined
调用undefined
作为state
参数时返回初始状态(实现它的最简单方法是指定state
ES6默认参数值),你就是对组合减速器有一个很好的有用行为。 他们更喜欢传递给createStore()
函数的initialState
对象中的相应值,但如果没有传递任何值,或者未设置相应的字段,则选择reducer指定的默认state
参数。 这种方法很有效,因为它提供了现有数据的初始化和水合作用,但如果不保留数据,则允许各个reducers重置其状态。 当然,您可以递归地应用此模式,因为您可以在许多级别上使用combineReducers()
,甚至可以通过调用reducers并将它们赋予状态树的相关部分来手动组合combineReducers()
。
简而言之:Redux是将初始状态传递给reducer的人,你不需要做任何事情。
当你调用createStore(reducer, [initialState])
你会让Redux知道在第一个动作进入时传递给reducer的初始状态是什么。
您提到的第二个选项仅适用于您在创建商店时未通过初始状态的情况。 即
function todoApp(state = initialState, action)
只有在Redux没有通过状态时才会初始化状态
你如何从商店中读取该状态并将其作为减速器中的第一个参数?
combineReducers()为您完成工作。 写它的第一种方式并不是真的有用:
const rootReducer = combineReducers({ todos, users })
但另一个,相当于更清楚:
function rootReducer(state, action) {
todos: todos(state.todos, action),
users: users(state.users, action)
}
我希望这能回答你的请求(我理解为在传递intialState并返回该状态时初始化reducers)
这就是我们这样做的方法(警告:从Typescript代码中复制)。
它的要点是mainReducer(工厂)函数中的if(!state)
测试
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 ) {
....
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.