【问题标题】:Updating a state in a slice, with object as a payload [duplicate]更新切片中的状态,将对象作为有效负载 [重复]
【发布时间】:2021-09-03 08:15:48
【问题描述】:

我有这个切片:

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { IAuthState } from '../../types';

const initialState: IAuthState = {
  isAuthenticated: false,
  profile: null,
};

export const authSlice = createSlice({
  name: 'auth',
  initialState,
  reducers: {
    setAuthState(state, { payload }: PayloadAction<IAuthState>) {
      console.log({ payload });
      state = payload;
    },
  },
});

export const { setAuthState } = authSlice.actions;
export const authReducer = authSlice.reducer;

这是标准样板切片。

问题是,如果我这样做,我的状态不会更新。 Redux devtools 说没有变化。我的有效载荷是这样的:

{
    isAuthenticated: true,
    profile: {...} // big object
}

但如果我这样分配:

 reducers: {
    setAuthState(state, { payload }: PayloadAction<IAuthState>) {
      state.isAuthenticated = payload.isAuthenticated;
      state.profile = payload.profile
    },
  },

它更新状态。这是为什么?以及如何批量更新整个状态?

【问题讨论】:

  • 好吧,这行得通。但是为什么我的尝试不起作用,为什么这会起作用?我认为整个 immer 的东西在后台“捕捉”了状态的变化。
  • state 是一个本地标识符,重新分配它不会在函数之外执行任何操作。但是,在 JS 中,对象是“通过引用”传递的(不完全是,但足够接近),所以在函数内部改变对象也会在函数外部引用它的任何地方改变相同的对象。
  • 是的。只是不确定为什么返回更新状态。如果我做了state.profile=payload.profile,会发生这种情况吗?
  • Redux Toolkit 通过让开发人员改变状态对象来简化状态更新,这通常在不可变状态中被禁止。 Redux Toolkit 通过传递一些可以改变而不改变实际状态的代理对象来实现这一点。返回一个新对象只会替换整个状态并忽略代理对象。

标签: javascript reactjs typescript redux redux-toolkit


【解决方案1】:

如何更新整个状态?

无论是使用 Redux Toolkit 的切片还是基本的 Redux reducer,如果您想替换整个状态,只需返回一个全新的值。

setAuthState(state, { payload }: PayloadAction<IAuthState>) {
  return payload; // replaces the whole state
},

为什么返回而不是分配更新状态?

 state = payload;

state 是一个本地标识符,重新分配它在函数之外没有任何作用。尽管在 JavaScript 中 object references are passed by value,所以在函数内部改变 state 对象也会在函数外部引用它的任何地方改变相同的对象。

Redux Toolkit simplifies state updates 通过让开发人员改变传递的state 对象,这通常被immutable states 禁止,就像在香草Redux 或React 状态中一样。

它在内部使用Immer 库,它允许您编写代码来“改变”某些数据,但实际上应用更新是不可变的。这使得实际上不可能在 reducer 中意外地改变状态。

在reducer中返回一个新对象只会替换整个状态并忽略代理对象。

如果我做了state.profile=payload.profile,会发生这种情况吗?

是的,显式地改变每个属性(利用 RTK 对 Immer 的使用)会做同样的事情,但需要更多的代码。虽然如果有效负载有任何属性,它们将不会包含在切片的状态中。

这可能是你想要的,没有任何不需要的数据在没有明确添加到减速器的情况下进入状态。所以说清楚也不是坏事。

但是,如果您有很多属性,那么维护起来可能会很烦人。

setAuthState(state, { payload }) {
  state.isAuthenticated = payload.isAuthenticated;
  state.profile = payload.profile
  state.thing = payload.thing
  state.stuff = payload.stuff
  state.foo = payload.foo
  state.bar = payload.bar
  // etc...
},

如果我想要整个有效负载而不替换不相关的状态值怎么办?

如果payload 变长,但您不想替换整个状态,您可以做的是从传播当前状态和有效负载返回一个新对象。

setAuthState(state, { payload }) {
  return {
     ...state,
     ...payload,
  };
},

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-06
    相关资源
    最近更新 更多