Skip to content

React State Arrays: The Right Way to Add, Delete, & Update

Posted on:February 5, 2026 at 07:15 PM

Hello, Code Chefs! 👨‍🍳

Raise your hand if you’ve experienced this horror story: You have a list state (array), you try to add a new item using .push(). But… nothing happens on the screen. Even though console.log shows the data is there.

Is React broken? Nope. What’s wrong is how we treat the State.

In React, there is one golden rule: NEVER mutate state directly.

Today, we’re going to cook up the correct way to manipulate arrays in React state. Grab your coffee, let’s get cooking! ☕

Why push() and splice() are Forbidden

Look at this “naughty” code:

const [todos, setTodos] = useState(["Learn React", "Drink Coffee"]);

const addTodo = () => {
  // ❌ WRONG!
  todos.push("Take a nap");
  setTodos(todos);
};

Why doesn’t this work? Because .push() modifies the array in place (mutating). The memory reference of the array doesn’t change. React is smart but lazy. It checks: “Is the new array reference different from the old one?” If the reference is the same, React says: “Meh, data looks the same. No need to re-render.”

That’s why we must always create a new array whenever we update the state.

1. Adding Data (Add)

Use the Spread Operator (...). This is the easiest way to copy the old array into a new one.

const addTodo = (newTodo) => {
  // ✅ CORRECT!
  // We create a new array: [...oldData, newData]
  setTodos([...todos, newTodo]);
};

Want to add it to the front (unshift)? Just flip it: setTodos([newTodo, ...todos]);

2. Removing Data (Delete)

Don’t use .splice()! It’s messy and mutating. Use the .filter() method.

The concept: “Keep all items EXCEPT the one we want to remove.”

const deleteTodo = (indexToRemove) => {
  // ✅ CORRECT!
  setTodos(todos.filter((_, index) => index !== indexToRemove));
};

// Or using ID (recommended)
const deleteById = (id) => {
  setTodos(todos.filter((todo) => todo.id !== id));
};

3. Updating Data (Edit)

What if we want to change the status from “Incomplete” to “Complete”? Don’t access the index directly like todos[0].status = "Complete". That’s mutating!

Use the .map() method. The concept: “Loop through all items. If it matches the one we want, change it. If not, leave it alone.”

const toggleStatus = (id) => {
  // ✅ CORRECT!
  setTodos(
    todos.map((todo) => {
      if (todo.id === id) {
        // Copy old object, then overwrite 'completed' property
        return { ...todo, completed: !todo.completed };
      }
      // Leave other items alone
      return todo;
    })
  );
};

The Cheat Sheet

OperationForbidden (Mutating)Recommended (Immutable)
Addpush(), unshift()[...arr, item]
Removepop(), splice().filter()
Editarr[i] = x.map()
Sortsort(), reverse()[...arr].sort() (Copy first!)

Final Thoughts

Manipulating arrays immutably (without changing the original) might feel weird at first, especially if you’re used to standard algorithmic coding. But trust me, this is the key to keeping your React app bug-free and performant.

Bottom line: Always make a fresh copy, don’t touch the old one.

Hope this helps! If you’re still confused, let’s grab another coffee. ☕

Happy Coding! 🚀