在 Redux Reducer 中读取 Store 的初始状态 [英] Read Store's Initial State in Redux Reducer

查看:43
本文介绍了在 Redux Reducer 中读取 Store 的初始状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Initial state in a Redux app can be set in two ways:

  • 将它作为第二个参数传递给 createStore(docs 链接)
  • 将它作为第一个参数传递给您的(子)reducers(文档链接)

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

If you pass initial state to your store, how do you read that state from the store and make it the first argument in your reducers?

推荐答案

TL;DR

如果没有 combineReducers() 或类似的手动代码,initialState 在 reducer 中总是胜过 state = ... 因为 state 传递给 reducer is initialState 并且 is not undefined,所以 ES6 参数语法不在这种情况下不适用.

TL;DR

Without combineReducers() or similar manual code, initialState always wins over state = ... in the reducer because the state passed to the reducer is initialState and is not undefined, so the ES6 argument syntax doesn't get applied in this case.

使用 combineReducers() 时,行为更加微妙.那些状态在 initialState 中指定的 reducer 将接收到那个 state.其他 reducer 将收到 undefined 并且因此 将回退到他们指定的 state = ... 默认参数.

With combineReducers() the behavior is more nuanced. Those reducers whose state is specified in initialState will receive that state. Other reducers will receive undefined and because of that will fall back to the state = ... default argument they specify.

一般来说,initialState 会胜过reducer 指定的状态.这让 reducer 可以指定对他们有意义的初始数据作为默认参数,但也允许在您从某些持久存储或服务器中加载存储时(全部或部分)加载现有数据.强>

In general, initialState wins over the state specified by the reducer. This lets reducers specify initial data that makes sense to them as default arguments, but also allows loading existing data (fully or partially) when you're hydrating the store from some persistent storage or the server.

首先让我们考虑一个只有一个 reducer 的情况.
假设您不使用 combineReducers().

First let's consider a case where you have a single reducer.
Say you don't use combineReducers().

那么你的减速器可能看起来像这样:

Then your reducer might look like this:

function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT': return state + 1;
  case 'DECREMENT': return state - 1;
  default: return state;
  }
}

现在假设您用它创建了一个商店.

Now let's say you create a store with it.

import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState()); // 0

初始状态为零.为什么?因为 createStore 的第二个参数是 undefined.这是第一次传递给您的减速器的 state.当 Redux 初始化时,它会调度一个虚拟"动作来填充状态.所以你的 counter 减速器被调用,state 等于 undefined.这正是激活"默认参数的情况.因此,根据默认的statestate现在是0代码> 值(state = 0).将返回此状态 (0).

The initial state is zero. Why? Because the second argument to createStore was undefined. This is the state passed to your reducer the first time. When Redux initializes it dispatches a "dummy" action to fill the state. So your counter reducer was called with state equal to undefined. This is exactly the case that "activates" the default argument. Therefore, state is now 0 as per the default state value (state = 0). This state (0) will be returned.

让我们考虑一个不同的场景:

Let's consider a different scenario:

import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState()); // 42

为什么这次是42,而不是0?因为 createStore 是用 42 作为第二个参数调用的.这个参数成为传递给你的减速器的 state 以及虚拟动作.这一次,state不是未定义的(它是42!),所以ES6的默认参数语法没有作用. state4242是reducer返回的.

Why is it 42, and not 0, this time? Because createStore was called with 42 as the second argument. This argument becomes the state passed to your reducer along with the dummy action. This time, state is not undefined (it's 42!), so ES6 default argument syntax has no effect. The state is 42, and 42 is returned from the reducer.

现在让我们考虑使用 combineReducers() 的情况.
你有两个减速器:

Now let's consider a case where you use combineReducers().
You have two reducers:

function a(state = 'lol', action) {
  return state;
}

function b(state = 'wat', action) {
  return state;
}

combineReducers({ a, b }) 生成的reducer如下所示:

The reducer generated by combineReducers({ a, b }) looks like this:

// 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 在调用 a 时将是 undefinedb 减速器.ab 减速器都将接收 undefined 作为他们的 state 参数, 如果他们指定了默认的 state 值,这些值将被返回. 这就是组合的 reducer 返回一个 { a: 'lol', b: 'wat' } 第一次调用时的状态对象.

If we call createStore without the initialState, it's going to initialize the state to {}. Therefore, state.a and state.b will be undefined by the time it calls a and b reducers. Both a and b reducers will receive undefined as their state arguments, and if they specify default state values, those will be returned. This is how the combined reducer returns a { a: 'lol', b: 'wat' } state object on the first invocation.

import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState()); // { a: 'lol', b: 'wat' }

让我们考虑一个不同的场景:

Let's consider a different scenario:

import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState()); // { a: 'horse', b: 'wat' }

现在我指定了 initialState 作为 createStore() 的参数.从组合减速器返回的状态结合我为 a 减速器指定的初始状态与 'wat' 默认参数指定 b reducer 选择了自己.

Now I specified the initialState as the argument to createStore(). The state returned from the combined reducer combines the initial state I specified for the a reducer with the 'wat' default argument specified that b reducer chose itself.

让我们回想一下组合式减速器的作用:

Let's recall what the combined reducer does:

// 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' } 作为回报.

In this case, state was specified so it didn't fall back to {}. It was an object with a field equal to 'horse', but without the b field. This is why the a reducer received 'horse' as its state and gladly returned it, but the b reducer received undefined as its state and thus returned its idea of the default state (in our example, 'wat'). This is how we get { a: 'horse', b: 'wat' } in return.

总而言之,如果您坚持 Redux 约定并在使用 undefined 作为 state 参数调用 reducer 时从它们返回初始状态(最简单的方法)实现这一点是指定 state ES6 默认参数值),你将有一个很好的组合减速器的有用行为.他们会更喜欢您传递给 createStore() 函数的 initialState 对象中的相应值,但如果您没有传递任何值,或者如果相应字段未设置,则选择由reducer 指定的默认state 参数. 这种方法很有效,因为它提供了现有数据的初始化和水合,但如果出现以下情况,则允许各个reducer 重置它们的状态他们的数据没有保留.当然,您可以递归地应用此模式,因为您可以在多个级别上使用 combineReducers(),甚至可以通过调用 reducers 并为它们提供状态树的相关部分来手动组合 reducer.

To sum this up, if you stick to Redux conventions and return the initial state from reducers when they're called with undefined as the state argument (the easiest way to implement this is to specify the state ES6 default argument value), you're going to have a nice useful behavior for combined reducers. They will prefer the corresponding value in the initialState object you pass to the createStore() function, but if you didn't pass any, or if the corresponding field is not set, the default state argument specified by the reducer is chosen instead. This approach works well because it provides both initialization and hydration of existing data, but lets individual reducers reset their state if their data was not preserved. Of course you can apply this pattern recursively, as you can use combineReducers() on many levels, or even compose reducers manually by calling reducers and giving them the relevant part of the state tree.

这篇关于在 Redux Reducer 中读取 Store 的初始状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆