【问题标题】:JS spread operator workflow on ReactReact 上的 JS 扩展运算符工作流程
【发布时间】:2022-01-12 05:58:26
【问题描述】:

React 建议不要改变状态。我有一组对象,我正在根据一些事件进行操作。我的问题是,这样写可以吗:

const makeCopy = (arr) => arr.map((item) => ({ ...item }));

function SomeComponenet() {
    const [filters, setFilters] = useState(aemFilterData);

    const handleFilterClick = (filter, c) => {
        let copiedFilters = makeCopy(filters);

        /**
         * Apply toggle on the parent as well
         */
        if (!("parentId" in filter)) {
            copiedFilters[filter.id].open = !copiedFilters[filter.id].open;
        }
        setFilters(copiedFilters);
    }
}

我是否像上面那样改变了原始对象?还是这样写有区别吗:

const makeCopy = (arr) => arr.map((item) => ({ ...item }));

function SomeComponent() {
    const [filters, setFilters] = useState(aemFilterData);

    const handleFilterClick = (filter, c) => {
        let copiedFilters = makeCopy(filters);

        /**
         * Apply toggle on the parent as well
         */
        if (!("parentId" in filter)) {
            copiedFilters = copiedFilters.map((f) => {
            if (filter.id === f.id) {
              return {
                ...f,
                open: !f.open,
              };
            } else {
              return { ...f };
            }
          });
        }
        setFilters(copiedFilters);
    }
}

执行此操作的首选方法是什么?扩展运算符变得非常冗长,我不喜欢它,但如果我需要在这里这样做,我更喜欢它。 immutable.js 和 immer 或不是现在的选项。

【问题讨论】:

  • 使用 JSON 进行深拷贝 --> stackoverflow.com/a/47690512/12509535
  • 地图复制就够了,不用每一项都复制
  • childIds 数组不会使用扩展运算符克隆,并且容易受到两个对象的更改,因为它们将共享相同的...jsfiddle.net/aejgupLs
  • as long as I am not using some nested item within the state object as a dependency, it won't be an issue? 是的,正确,这不是问题。 Is my understanding correct? 好像是这样。 Does this mean I can safely consider the first approach above? 是的,实际上您的第一种方法已经是矫枉过正了。您甚至克隆了数组中的所有项目。只克隆数组就足够了,因此这样做const copiedFilters = [...filters] 就足够了。不需要你的makeCopy 函数。
  • Here 是一个涵盖您的用例的问题。查看接受的答案。

标签: javascript reactjs immutability spread


【解决方案1】:
const makeCopy = (arr) => arr.map((item) => item );

使用上面的代码,它会在原始对象引用上发生变异,因为我们没有创建深度克隆。

copiedFilters[filter.id].open = !copiedFilters[filter.id].open;

这里copiedFilters[filter.id]filters[filter.id]的引用是一样的。

使用扩展运算符

const makeCopy = (arr) => arr.map((item) => ({ ...item }));

在这里,我们也创建了内部对象的新副本。所以copiedFilters[filter.id]filters[filter.id] 会有不同的引用。

这与您的第二种方法相同。

因此,您可以在制作副本时使用扩展运算符,也可以在第二种方法中跳过制作副本并直接映射到filters,因为您在那里使用了扩展运算符。这看起来更好,因为为什么要运行两次循环 - 首先创建副本,然后更新 open

// let copiedFilters = makeCopy(filters); Not needed in second approach
copiedFilters = copiedFilters.map((f) => {
  if (filter.id === f.id) {
    return {
      ...f,
      open: !f.open,
    };
  } else {
    return { ...f };
  }
});

您可以在复制时创建深度克隆,但这会浪费计算和内存,我认为这里不需要。 当您在对象中进一步嵌套时,深层克隆会很有帮助。

【讨论】:

  • 我想我会根据您的建议坚持第二种方法;考虑到,我在其他地方有活动,如果性能较差,我不想到处进行深度克隆。
  • 我的代码中充满了这样的map和spread操作。我想知道我是否可以深度克隆并直接修改它们。是否会对性能产生巨大影响,或者考虑到可读性会大大提高,是否可以权衡取舍。
  • 您必须衡量性能影响。在大多数情况下,您不会看到任何区别,但理论上 deepclone 应该很昂贵。不过,像 ImmutableJS 这样的库可能会做得更好。
  • 在你的回答中,你提到了copiedFilters[filter.id] and filters[filter.id] is same的引用。你能检查一下这个小提琴,因为我注意到它们是不同的吗?由于没有进一步的嵌套,我觉得它有效。 jsfiddle.net/vcnd7woj
  • @ThomasSebastian 在小提琴中,您使用的是扩展运算符,但如果您有 arr.map((item) => item );,那么参考将是相同的
猜你喜欢
  • 2019-08-10
  • 2022-08-03
  • 2016-08-08
  • 2020-08-10
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-13
相关资源
最近更新 更多