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

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?

>Solution :

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.

Leave a Reply