To update arrays in React state, replace the array with a new one instead of mutating it. Methods like push and splice change the existing array, so React skips the update. Build the new array with spread, filter, map, and slice instead, the same way you replace objects.
Treat arrays as read-only
Arrays in JavaScript are objects, and the same read-only rule applies. Mutating methods change the old array in place, which hides the change from React. The list below maps each common task to the method that returns a new array instead.
| Task | Avoid (mutates) | Prefer (returns a new array) |
|---|---|---|
| Add an item | push, unshift | spread, concat |
| Remove an item | pop, shift, splice | filter, slice |
| Replace an item | splice, arr[i] = value | map |
| Sort or reverse | sort, reverse | copy first |
The table is your quick reference. Every left-hand method changes the original array, and every right-hand option produces a fresh one. When in doubt, copy first and change the copy.
Add an item
Start with a list in state and spread it into a new array with the extra item at the end.
import { useState } from "react";
const [todos, setTodos] = useState([
{ id: 0, title: "Buy milk", done: false },
]);Calling the setter with a spread creates the next list without touching the old one. The spread copies the existing items and appends the new item at the end.
setTodos([...todos, { id: 1, title: "Write tests", done: false }]);The new array keeps the milk item and adds the tests item. React sees a different array, re-renders, and the list shows both. Prepend instead by placing the new item before the spread, and the existing items slide to the end.
Remove an item
Use filter to produce an array without the removed item. The callback returns true for items you want to keep and false for the one you are removing.
setTodos(todos.filter((todo) => todo.id !== 1));The result contains every todo except the one with id 1. filter never modifies the original array, so the previous list stays intact for React's comparison and the next render receives a different array. slice works the same way when you only need to drop items from one end.
Replace an item
Use map to return a new item in place of the old one. The callback receives each item and decides whether to return it unchanged or return a replacement.
setTodos(
todos.map((todo) =>
todo.id === 1 ? { ...todo, done: true } : todo
)
);Only the matching item is replaced, and it is replaced with a copied object rather than mutated. The other items are returned as they were, so their identity stays the same and React can skip re-rendering anything that did not change.
Insert at a position and reorder
Spread plus slice inserts an item at any index.
setTodos([
...todos.slice(0, 1),
{ id: 2, title: "New item", done: false },
...todos.slice(1),
]);The slice before the insertion point comes first, then the new item, then the rest. To reorder, copy the array first, then call sort or reverse on the copy, because both methods mutate their input. The full set of move and reorder operations is covered in removing, replacing, and reordering array items.
Common mistakes
These three slips produce the same silent symptom: the list never updates.
- Calling push or splice directly on state mutates it and skips the render.
- Copying the array but mutating an object inside it still mutates shared data.
- Using the index as a key breaks when the list is reordered, inserted into, or filtered, so use stable keys from the data.
What to learn next
Arrays often hold objects, so updating objects is the natural next skill. Both follow the same rule: never mutate, always replace. For deeply nested lists, Immer removes the copying ceremony once the plain methods feel repetitive.
Rune AI
Key Insights
- Never call push, pop, splice, sort, or reverse on state directly.
- Add items with spread or concat.
- Remove items with filter or slice.
- Replace items with map.
- Copy the array first before sorting or reversing.
Frequently Asked Questions
Why does push not update my list?
How do I sort or reverse an array in state?
Can I mutate an object inside a copied array?
Conclusion
Arrays in state are read-only. Add with spread or concat, remove with filter or slice, and replace with map. Copy first for sort and reverse, and never mutate the original.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.