Managing Array State & Immutable Updates
A masterclass tutorial covering Adding items, Removing items, Updating items, Array.prototype.map(), Array.prototype.filter(), Spread operator for arrays, Immutable array update patterns, Pitfalls, and Interview Questions.
What is Array State in React?
In web development, we frequently store arrays in component state (lists of todo items, shopping cart items, notification queues, message histories).
Just like objects, arrays in React state MUST be updated immutably without modifying the original array reference.
Mutating vs Non-Mutating Array Methods
| Action Type | Mutating Methods (โ DO NOT USE DIRECTLY) | Non-Mutating Methods (โ USE IN REACT STATE) |
|---|---|---|
| Adding Items | push(), unshift() | Spread operator [...arr, newItem], concat() |
| Removing Items | pop(), shift(), splice() | filter() |
| Updating Items | Direct index assignment arr[i] = val | map() |
| Sorting / Reversing | sort(), reverse() | toSorted(), [...arr].sort() |
Pattern 1 โ Adding Items to Array State
Use the spread operator ... to create a new array containing all old items plus the new item:
// Add item to END of array:
setItems(prev => [...prev, newItem]);
// Add item to START of array:
setItems(prev => [newItem, ...prev]);Pattern 2 โ Removing Items from Array State
Use Array.prototype.filter() to return a new array excluding the target item ID:
const handleDeleteItem = (idToDelete) => {
setItems(prev => prev.filter(item => item.id !== idToDelete));
};Pattern 3 โ Updating Specific Items in Array State
Use Array.prototype.map() to transform the target item while keeping all other items unchanged:
const handleToggleComplete = (targetId) => {
setItems(prev => prev.map(item => {
if (item.id === targetId) {
return { ...item, completed: !item.completed }; // Return NEW updated object
}
return item; // Return unmodified item
}));
};Common Mistakes with Array State
- Using
push()orsplice()directly:items.push(newItem); setItems(items);mutates existing memory reference and fails to trigger re-renders! - Mutating objects inside array during map():
item.completed = true; return item;. Always return a fresh object:{ ...item, completed: true }. - Sorting array state in-place:
items.sort()mutates original array. Use[...items].sort().
Top React Interview Questions on Array State
Q1: How do you append an item to an array in React state without mutating it?
*Answer*: Use the spread operator: setItems(prev => [...prev, newItem]).
Q2: Why should you use filter() instead of splice() to delete array state items?
*Answer*: splice() mutates the array in-place, whereas filter() returns a brand new array reference without altering original data.
Q3: How do you update a single item property inside an array of objects?
*Answer*: Use map() to locate the matching item ID and return a new object with spread properties ({ ...item, prop: val }).
Practical Hands-On Exercise โ Complete Interactive Todo Manager
Here is a complete interactive todo application demonstrating adding, toggling completion, deleting, and filtering array state:
// Complete Masterclass Array State Showcase (src/App.jsx)
import React, { useState } from 'react';
export default function App() {
const [todos, setTodos] = useState([
{ id: 1, text: "Learn React Component Architecture", completed: true },
{ id: 2, text: "Master State Immutability & Array Updates", completed: false }
]);
const [taskText, setTaskText] = useState("");
// Add Todo Handler
const handleAddTodo = (e) => {
e.preventDefault();
if (!taskText.trim()) return;
const newTodo = {
id: Date.now(),
text: taskText,
completed: false
};
setTodos(prev => [...prev, newTodo]);
setTaskText("");
};
// Toggle Completion Handler
const handleToggle = (id) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
// Delete Todo Handler
const handleDelete = (id) => {
setTodos(prev => prev.filter(todo => todo.id !== id));
};
return (
<div style={{ maxWidth: "550px", margin: "30px auto", padding: "24px", background: "#ffffff", border: "1px solid #cbd5e1", borderRadius: "16px" }}>
<h2 style={{ color: "#002057" }}>Lecture 12: Array State Masterclass Todo App</h2>
<form onSubmit={handleAddTodo} style={{ display: "flex", gap: "10px", marginBottom: "20px" }}>
<input
type="text"
value={taskText}
onChange={(e) => setTaskText(e.target.value)}
placeholder="Add a new masterclass task..."
style={{ flex: 1, padding: "10px", borderRadius: "6px", border: "1px solid #cbd5e1" }}
/>
<button type="submit" style={{ background: "#2506ad", color: "#fff", border: "none", padding: "10px 18px", borderRadius: "6px", fontWeight: "bold" }}>
Add Task
</button>
</form>
<ul style={{ listStyle: "none", padding: 0 }}>
{todos.map(todo => (
<li key={todo.id} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px", borderBottom: "1px solid #f1f5f9" }}>
<span
onClick={() => handleToggle(todo.id)}
style={{
textDecoration: todo.completed ? "line-through" : "none",
color: todo.completed ? "#94a3b8" : "#0f172a",
cursor: "pointer",
fontWeight: "500"
}}
>
{todo.completed ? "โ
" : "โญ "} {todo.text}
</span>
<button onClick={() => handleDelete(todo.id)} style={{ background: "#ef4444", color: "#fff", border: "none", padding: "6px 12px", borderRadius: "4px", cursor: "pointer" }}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}