在Redux Reducer中读取商店的初始状态
Redux应用程序中的初始状态可以通过两种方式设置:
- 把它作为
createStore的第二个parameter passing( docs link ) - 把它作为你的(子)reducer的第一个参数( docs link )
如果您将初始状态传递给您的商店,您如何从商店中读取该状态,并将其作为您的减速器中的第一个参数?
TL; DR
如果没有
combineReducers()或类似的手动代码,initialState总是在reducer中赢得state = ...,因为传递给reducer的state是initialState而不是undefined,所以在这种情况下ES6参数的语法不适用。与
combineReducers()的行为是更细微的。 那些状态在initialState指定的reducer将会收到这个state。 其他reducer将收到undefined,因为这将回落到他们指定的state = ...默认参数。一般来说,
initialState胜过reducer指定的状态。 这可以让reducer指定初始数据作为默认参数, 这些数据对于他们来说是有意义的,但也允许在从一些永久性存储或服务器为存储提供水分时加载现有数据(完全或部分)。
首先让我们考虑一个情况,你有一个reducer。
假设你不使用combineReducers() 。
那么你的减速器可能看起来像这样:
function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } }
现在让我们说,你创build一个商店。
import { createStore } from 'redux'; let store = createStore(counter); console.log(store.getState()); // 0
初始状态是零。 为什么? 因为createStore的第二个参数是undefined 。 这是第一次传递给你的减速器的状态。 Redux初始化时会发送一个“虚拟”动作来填充状态。 所以你的counter还原器被调用的state等于undefined 。 这正是“激活”默认参数的情况。 因此,根据默认state值( state = 0 ), state现在为state = 0 。 这个状态( 0 )将被返回。
我们来考虑一个不同的场景:
import { createStore } from 'redux'; let store = createStore(counter, 42); console.log(store.getState()); // 42
为什么这次是42而不是0呢? 因为使用42作为第二个参数调用createStore 。 这个论点成为通过虚假行为传递给你的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的时候是undefined的。 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()的参数。 从组合减速机返回的状态将为减速机指定的初始状态与指定为减速机select的'wat'默认参数组合。
让我们回顾一下减速机的作用:
// 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并很乐意返回它,但减速器收到undefined的state并因此返回了默认state (在我们的例子中, 'wat' )的想法 。 这就是我们如何获得{ a: 'horse', b: 'wat' }的回报。
总而言之,如果你坚持使用Redux约定,并且在使用undefined作为state参数调用reducers时返回初始状态(最简单的实现方法是指定state ES6默认参数值),那么对联合减速器有一个很好的有用的行为。 他们会更喜欢传递给createStore()函数的initialState对象中的对应值,但是如果没有传递任何对象,或者未设置相应的字段,则会select由reducer指定的默认state参数。 这种方法运行良好,因为它既提供了现有数据的初始化和水合,也允许个别减法器在其数据未被保留的情况下重置其状态。 当然,你可以recursion地应用这个模式,因为你可以在很多层次上使用combineReducers() ,甚至可以通过调用reducer并给它们赋予状态树的相关部分来手动组合reducers。
简而言之,Redux是将初始状态传递给reducer的人,你不需要做任何事情。
当你调用createStore(reducer, [initialState])时,让Redux知道在第一个动作进入时,传递给reducer的初始状态是什么。
您提到的第二个选项仅适用于在创build商店时未通过初始状态的情况。 即
function todoApp(state = initialState, action)
状态将只在Redux没有通过状态时才被初始化
我希望这回答你的请求(我理解为初始化减速器,同时通过intialState并返回该状态)
这是我们如何做到的(警告:从Typescript代码复制)。
它的要点是mainReducer(工厂)函数中的if(!state)testing
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()为你做这个工作。 写它的第一种方法并不是很有帮助:
const rootReducer = combineReducers({ todos, users })
但是另外一个,那就等于比较清楚了:
function rootReducer(state, action) { todos: todos(state.todos, action), users: users(state.users, action) }