为什么我在从反应对象复制状态时必须将对象展开两次

问题描述 投票:0回答:2

我下面有这个对象,我想测试当我执行操作来更改

group
键的状态时,它会正确更新。正如您所看到的,该对象中有更多的键值对,而不仅仅是
group
,因此我想扩展
initialState
对象并编写我的测试,仅更改
group
值。

这是初始状态:

export const initialState = {
  testing: false,
  filters: {
    start: moment()
      .startOf("month")
      .format(),
    end: moment()
      .endOf("month")
      .format(),
    city: "",
    group: "daily"
  },
  locations: []
};

我的单元测试:

test("It performs the setGroup action correctly", () => {
    const active = "month";

    const action = setGroup(active);

    const state = reducer(
      {
        ...initialState,
        filters: {
          ...initialState.filters,
          group: "daily"
        }
      },
      action
    );

    expect(state).toEqual({
      ...initialState,
      filters: {
        ...initialState.filters,
        group: "month"
      }
    });
  });

这个测试有效,但是我想知道为什么我必须将

initialstate
展开一次,然后在过滤器对象中再次展开
initialState.filters
只是为了操纵月份。

在我看来这应该很好用:

const state = reducer(
      {
        ...initialState,
        filters: {
          group: "daily"
        }
      },
      action
    );

我的问题是为什么我需要添加

initialState.filters
行才能使此测试可行。请有人帮我理解吗?我已经研究过但找不到任何东西。

javascript reactjs unit-testing javascript-objects spread-syntax
2个回答
1
投票

当您执行

...initialState.filters
时,您正在将
filters
对象散布在
initialState
上。您必须执行此操作,因为您刚刚在减速器中定义了一个新的
filters
对象,因此必须在其中放置您想要从旧版本中保留的值。

如果这一切看起来有点冗长,那么请查看 Immer,它允许您使用更传统的 API 来拥有不可变对象

https://immerjs.github.io/immer/docs/introduction


1
投票

JavaScript 的扩展运算符相当愚蠢;它不会像某些库提供的那样尝试进行任何类型的智能合并。当您添加

filters
属性时,JavaScript 只会覆盖
initialState
的扩展
filters
定义。

您可以将代码示例视为大致相当于

Object.assign(
  {},
  initialState,
  {
    filters: { ... }
  })
© www.soinside.com 2019 - 2024. All rights reserved.