Redux应用程序中的初始状态可以通过两种方式设置:
如果将初始状态传递给商店,您如何从商店读取该状态并将其作为化简器中的第一个参数?
Answers:
TL; DR
没有
combineReducers()
或没有类似的手动代码,initialState
总会state = ...
在化简器中胜出,因为state
传递给化简器的isinitialState
和notundefined
,因此在这种情况下不会应用ES6参数语法。随着
combineReducers()
行为更加细微差别。在状态中指定的那些减速器initialState
将接收到state
。其他的reducer将会收到undefined
,因此将退回到state = ...
它们指定的默认参数。通常,
initialState
胜过减速器指定的状态。这使reducer可以将对它们有意义的初始数据指定为默认参数,但是当您从某个持久性存储或服务器对存储进行连接时,也可以(全部或部分)加载现有数据。
首先,让我们考虑一个单独的减速器的情况。
说你不使用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
reducer被称为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
被称为带有42
第二个参数。该参数state
与伪动作一起传递给减速器。这次state
不是未定义的(是42
!),因此ES6默认参数语法无效。的state
是42
,和42
从减速机返回。
现在考虑使用的情况combineReducers()
。
您有两个减速器:
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
由生成的reducercombineReducers({ 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
值,这些将被退回。这就是组合化归约器{ 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约定,并在将reducerundefined
作为state
参数调用时从reducer返回初始状态(最简单的实现方法是指定state
ES6默认参数值),对于组合减速器而言,这是一个很好的有用行为。他们会首选initialState
传递给createStore()
函数的对象中的对应值,但是如果没有传递任何值,或者未设置对应字段,则将state
选择由reducer指定的默认参数。这种方法之所以行之有效,是因为它既提供了现有数据的初始化功能,又提供了对现有数据的水合处理功能,但是,如果未保存其数据,则可以让单个化简机重置其状态。当然,您可以递归地应用此模式,因为您可以combineReducers()
在多个级别上使用它,甚至可以通过调用化简器并将其提供给状态树的相关部分来手动编写化简器。
function counter(state = 0, action)
或function visibleIds(state = [], action)
。
简而言之:Redux是将初始状态传递给reducer的人,您无需执行任何操作。
当您打电话时,createStore(reducer, [initialState])
您是在让Redux知道第一个操作进入时要传递给reducer的初始状态是什么。
您提到的第二个选项仅在创建商店时未通过初始状态的情况下适用。即
function todoApp(state = initialState, action)
仅当Redux没有传递状态时,状态才会被初始化
menuState
,我如何告诉菜单reducerstate.menu
从存储中读取值并将其用作初始状态?
我希望这能回答您的请求(我理解为在传递intialState并返回该状态的同时初始化reducers)
这是我们的操作方式(警告:从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 ) {
....
}
}
}
combineReducers
。再次非常感谢你。