Updating Objects and Arrays in State
โš›๏ธ React 18+ ๐ŸŸข Chapter 13 of 39 ๐Ÿ“‚ Phase 05: Events and State ๐Ÿ“… 2026 Edition
๐Ÿ“Œ Covered in this chapter: Immutability ยท Object Update with Spread ยท Array Add/Remove/Update ยท map()/filter() with State ยท Nested Objects ยท Form State Object
Objects and arrays in state need special handling โ€” React relies on detecting a new object reference to know something changed, so state must always be updated immutably, never mutated directly.
1Why You Can't Mutate State Directly
// โŒ Wrong - mutating state directly
const [user, setUser] = useState({ name: "Ravi", age: 20 });
user.age = 21;  // React has no way to know this happened
setUser(user);  // same object reference - React may skip the re-render entirely

React compares object references to decide whether to re-render, not deep contents. Mutating the existing object and passing the same reference back to setUser() means React might not detect any change at all.

2Updating Objects with the Spread Operator
๐Ÿ’ป Example 1: Correct Object State Update
const [user, setUser] = useState({ name: "Ravi", age: 20 });

function haveBirthday() {
  setUser((previousUser) => ({
    ...previousUser,
    age: previousUser.age + 1
  }));
}

...previousUser copies every existing property into a brand-new object, and age: previousUser.age + 1 overwrites just that one field โ€” React sees a genuinely new object reference and re-renders correctly.

3Adding, Removing, and Updating Array Items in State
const [todos, setTodos] = useState(["Learn JSX", "Learn Props"]);

// Add - spread the old array into a new one
function addTodo(text) {
  setTodos((prev) => [...prev, text]);
}

// Remove - filter creates a new array without the removed item
function removeTodo(index) {
  setTodos((prev) => prev.filter((_, i) => i !== index));
}

// Update - map creates a new array with one item changed
function updateTodo(index, newText) {
  setTodos((prev) => prev.map((todo, i) => (i === index ? newText : todo)));
}

Notice the pattern: filter() and map() both naturally return new arrays without touching the original โ€” this is exactly why they're the standard tools for updating array state, instead of methods like push() or splice() which mutate in place.

โš ๏ธ Using push() or splice() on State Arrays

todos.push(newItem) mutates the existing array in place, exactly like the object mutation mistake above โ€” React may not detect the change and won't re-render. Always create a new array using spread, map(), or filter(), and pass that new array to your state setter.

๐Ÿ’ป Hands-on Interactive Practice Challenge

Build a simple todo list where you can add a new item and remove an item by index, using proper immutable array updates.

React Practice Challenge โ–ถ Run in Compiler
import { useState } from "react";

function TodoApp() {
  const [todos, setTodos] = useState(["Learn React"]);

  function addTodo() {
    setTodos(prev => [...prev, "New Task"]);
  }

  function removeTodo(index) {
    setTodos(prev => prev.filter((_, i) => i !== index));
  }

  return (
    <div>
      <button onClick={addTodo}>Add</button>
      <ul>
        {todos.map((todo, i) => (
          <li key={i}>
            {todo} <button onClick={() => removeTodo(i)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
}
Run This Challenge in Online JS IDE โ†’
โ“ Frequently Asked Questions (FAQ)

Q What does 'immutability' actually mean in React?

It means never changing an existing object or array in place โ€” instead, always create a brand-new copy (using spread, map, or filter) with the desired changes, and pass that new copy to your state setter.

Q Why does React care about object references instead of just comparing values?

Deeply comparing every value inside every object on every render would be slow at scale. Comparing references (is this the exact same object in memory?) is extremely fast, which is why React relies on you creating new objects/arrays to signal that something actually changed.

OC
Written by Our Compiler Technical Editorial Team
Reviewed for accuracy & tested on React 18+ ยท Last updated August 2026