繁体   English   中英

在Redux Reducer中读取Store的初始状态

[英]Read Store's Initial State in Redux Reducer

Redux应用程序中的初始状态可以通过两种方式设置:

  • 将它作为createStore的第二个参数传递( docs链接
  • 将它作为第一个参数传递给(子)减速器( docs link

如果您将初始状态传递到商店,那么如何从商店中读取该状态并将其作为减速器中的第一个参数?

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默认参数语法无效。 state42 ,从减速器返回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.astate.b将在调用ab reducers时被undefined ab 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收到减速undefinedstate ,从而恢复默认的思想 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM