Redux应用程序中的初始状态可以通过两种方式设置:
createStore
如果将初始状态传递给商店,您如何从商店读取该状态并将其作为化简器中的第一个参数?
TL; DR 没有combineReducers()或没有类似的手动代码,initialState总是state = ...在化简器中胜出,因为state传递给化简器的 是 initialState和 不是 undefined,因此在这种情况下不会应用ES6参数语法。 随着combineReducers()行为更加细微差别。在状态中指定的那些减速器initialState将接收到state。其他reducer将会收到undefined ,因此 将退回到state = ...它们指定的默认参数。 通常,initialState胜过减速器指定的状态。这使reducer可以将对 它们 有意义的初始数据指定为默认参数,但是当您从某个持久性存储或服务器对存储进行连接时,也可以(全部或部分)加载现有数据。
没有combineReducers()或没有类似的手动代码,initialState总是state = ...在化简器中胜出,因为state传递给化简器的 是 initialState和 不是 undefined,因此在这种情况下不会应用ES6参数语法。
combineReducers()
initialState
state = ...
state
undefined
随着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减速器被称为state等于undefined。 这就是“激活”默认参数的情况。 因此,state现在0是默认state值(state = 0)。此状态(0)将返回。
counter
0
state = 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从减速机返回。
42
现在考虑使用的情况combineReducers()。 您有两个减速器:
function a(state = 'lol', action) { return state; } function b(state = 'wat', action) { return state; }
由生成的reducer 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) }; }
如果我们在createStore没有调用的情况下调用initialState,则会将其初始化state为{}。因此,state.a并state.b会undefined通过它调用的时间a和b减速。 双方a和b减速会收到undefined作为 他们的 state论点,如果他们指定默认state值,这些将被退回。这就是组合化归约器{ a: 'lol', b: 'wat' }在第一次调用时返回状态对象的方式。
{}
state.a
state.b
a
b
{ 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。
createStore()
'wat'
让我们回想一下组合减速器的作用:
在这种情况下,state已指定,因此它不会退回到{}。它是一个a字段等于'horse',但没有该b字段的对象。这就是为什么areducer收到'horse'其作为state并乐意返回它的原因,而breducer收到undefined其作为state并因此返回 其 默认值的 想法state(在我们的示例中为'wat')。这就是我们获得{ a: 'horse', b: 'wat' }回报的方式。
'horse'
{ a: 'horse', b: 'wat' }
综上所述,如果您坚持使用Redux约定,并在将reducer undefined作为state参数调用时从reducer返回初始状态(最简单的实现方法是指定stateES6默认参数值),对于组合减速器而言,这是一个很好的有用行为。 他们会首选initialState传递给createStore()函数的对象中的相应值,但是如果您没有传递任何值,或者未设置相应字段,则将state选择由reducer指定的默认参数。这种方法之所以有效,是因为它既提供了现有数据的初始化功能,又提供了水合功能,但是如果未保存其数据,则可以让单个化简机重置其状态。当然,您可以递归地应用此模式,因为您可以combineReducers()在多个级别上使用它,甚至可以通过调用化简器并将其提供给状态树的相关部分来手动组成化简器。