Javascript 从react对象复制状态时,为什么必须将对象展开两次

Javascript 从react对象复制状态时,为什么必须将对象展开两次,javascript,reactjs,unit-testing,javascript-objects,spread,Javascript,Reactjs,Unit Testing,Javascript Objects,Spread,我在下面有一个对象,我想测试一下,当我执行一个操作,将组的状态更改为正确更新的状态时。正如您所看到的,这个对象中的键值对远远多于组,因此我想扩展初始状态对象,并编写我的测试,只更改组值 以下是初始状态: export const initialState = { testing: false, filters: { start: moment() .startOf("month") .format(), end: moment() .e

我在下面有一个对象,我想测试一下,当我执行一个操作,将
组的状态更改为正确更新的状态时。正如您所看到的,这个对象中的键值对远远多于
,因此我想扩展
初始状态
对象,并编写我的测试,只更改

以下是初始状态:

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
一次,然后在filters对象中再次传播
initialstate。filters
再次传播只是为了操纵月份

在我看来,这应该很好:

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

我的问题是为什么我需要将行
initialState.filters
放入测试中。有人能帮我理解吗?我做过研究,但什么也找不到。

JavaScript的扩展操作符相当愚蠢;它不会像一些图书馆提供的那样尝试进行任何形式的智能合并。当您添加
过滤器
属性时,JavaScript只会覆盖
初始状态
的扩展
过滤器
定义

您可以认为您的代码示例大致相当于

Object.assign(
  {},
  initialState,
  {
    filters: { ... }
  })

JavaScript的扩展操作符相当愚蠢;它不会像一些图书馆提供的那样尝试进行任何形式的智能合并。当您添加
过滤器
属性时,JavaScript只会覆盖
初始状态
的扩展
过滤器
定义

您可以认为您的代码示例大致相当于

Object.assign(
  {},
  initialState,
  {
    filters: { ... }
  })

当您执行
…initialState.filters
时,您正在扩展
initialState
上的
filters
对象。您必须这样做,因为您刚刚在reducer中定义了一个新的
过滤器
对象,因此必须在其中放置希望保留旧版本的值

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


当您执行
…initialState.filters
时,您正在
initialState
上展开
filters
对象。您必须这样做,因为您刚刚在reducer中定义了一个新的
过滤器
对象,因此必须在其中放置希望保留旧版本的值

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


这有助于我理解。因此,为了澄清,当我第一次传播
initialState
对象时,我将对象作为一个整体进行新的复制。然后,我必须从这个新的
initialState
中说一些类似的话,我想保留filters对象(
…initialState.filters
)和
值在其中。几乎,当您向其添加或更改值时,您已经在重新定义
过滤器时执行了第二个操作。这有助于我理解。因此,为了澄清,当我第一次传播
initialState
对象时,我将对象作为一个整体进行新的复制。然后我必须从这个新的
initialState
中说一些类似的话,我想保留filters对象(
…initialState.filters
)和
值在其中。几乎,当您向其添加或更改值时,在重新定义
filters
时,您已经执行了第二个操作。