React useState 行为,关于需要使用扩展(…)操作符的问题。

huangapple go评论71阅读模式
英文:

React useState behaviour , questions on the need of a spread (....) operator

问题

以下是您要翻译的内容:

"why cant I return expenses1 without spreading it in an array? since expenses1 which is the previous data is an array containing an object? from what i can see, {listOfExpenses} takes in an array of objects which is === expenses1"

所以,我尝试过使用控制台记录并比较了expenses1和listOfExpenses之间的数据差异,它们都是相同的数据类型,因此为什么需要将其展开成一个数组?

英文:

why cant I return expenses1 without spreading it in an array? since expenses1 which is the previous data is an array containing an object? from what i can see, {listOfExpenses} takes in an array of objects which is === expenses1

import Expenses from "./components/Expenses/Expenses";
import NewExpenses from "./components/NewExpenses/NewExpenses";
import React, { useState } from "react";

const expenses = [
  { id: "e1", title: "Toilet Paper", amount: 94.12, date: new Date(2020, 7, 14),},
  { id: "e2", title: "New TV", amount: 799.49, date: new Date(2021, 2, 12), },
  { id: "e3", title: "Car Insurance", amount: 294.67, date: new Date(2021, 2, 28),},
  { id: "e4", title: "New Desk (Wooden)", amount: 450, date: new Date(2021, 5, 12), },
];

function App() {
  const [listOfExpenses, setListOfExpenses] = useState(expenses);
  const addExpenseHandler = (expenseData) => {
    setListOfExpenses((expenses1) => {
      console.log(expenses1);
      expenses1.push(expenseData);
      console.log(...expenses1);

      return [...expenses1];
    });
  };

 return (
   <div>
     <NewExpenses onAddExpense={addExpenseHandler} />
     <Expenses expenses={listOfExpenses} />
   </div>
 );
}

So I've tried console logging and compare the data difference between expenses1 and listOfExpenses, they are both the same data type thus why the need of spreading in an array?

答案1

得分: 3

因为React状态的第一条规则是不要直接修改状态,这包括不要修改存储在状态中的对象的状态(如数组),请参阅文档。如果您不返回与状态中的数组不同的数组,React将不会看到任何差异,并且可能无法正确重新渲染。

您使用的展开操作仍然在技术上是不正确的(尽管我认为它在很大程度上是无害的),它应该在添加到数组之前(或同时)复制数组,而不是添加到状态中的数组(这会导致变异,这是不允许的)。通过复制先前的数组并添加元素可以使用单个数组文字来完成:

setListOfExpenses((expenses) => {
    return [...expenses, expenseData];
});

或者甚至可以简化为:

setListOfExpenses((expenses) => [...expenses, expenseData]);
英文:

> why cant i "return expenses1" without spreading it in an array

Because the first rule of React state is do not modify state directly, which includes not modifying the state of objects that are held in state (like arrays), see the documentation. If you don't return a different array than the one in state, React doesn't see a difference, and doesn't necessarily re-render properly.

The code you have that is using spread is still technically incorrect (though largely harmless I suspect), it should be copying the array before adding to it (or at the same time), not adding it to the array in state (which mutates it, which you mustn't do). Creating a new array by copying a previous one and adding an element can be done with a single array literal:

setListOfExpenses((expenses) => {
    return [...expenses, expenseData];
});

or even

setListOfExpenses((expenses) => [...expenses, expenseData]);

答案2

得分: 3

不要在React(或Redux或RxJs等)中更改数据结构。

.push()方法会更改现有的数组。这意味着它将更新对该数组的所有引用,包括内部用于跟踪需要更新的引用。由于旧数组和新数组相等,React不会进行更新。

相反,您应该始终创建一个新数组。虽然使用展开运算符来复制数组在技术上可以工作,但这只是因为JS中的等号运算符不太好。要正确执行此操作,请使用:

setListOfExpenses(expenses => [...expenses, expenseData])

这将创建一个新数组,从原始费用开始,然后将expenseData添加到末尾。这永远不会更改原始数组,因此在所有情况下都会正确更新,即使对于使用适当的相等性检查的库也是如此。

英文:

You should never mutate data structures in React (or Redux or RxJs etc.)

The .push() method will mutate the existing array. This means it will update all references to that array, including the one internally uses to keep track of what needs to be updated. Since the old array and new array are equal, react won't update.

Instead, you should always make a new array. While the spread operator, which will copy the array will technically work, it's only because the equality operator in JS is not very good. Do do it properly use:

setListOfExpenses(expenses=>[...expenses, expenseData])

This will create a new array that starts with the original expenses, then adds the expenseData to the end. This will never mutate the original array, so properly update in all cases, even for libraries that use proper equality checks.

huangapple
  • 本文由 发表于 2023年2月8日 18:39:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75384569.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定