The spread operator ... expands an array or object into its individual elements. It’s how you copy, merge, and build new data structures without mutating the originals.
const colors = ["red", "green", "blue"];// Add to the endconst withYellow = [...colors, "yellow"];// ["red", "green", "blue", "yellow"]// Add to the beginningconst withWhite = ["white", ...colors];// ["white", "red", "green", "blue"]// Insert in the middleconst withOrange = [...colors.slice(0, 2), "orange", ...colors.slice(2)];// ["red", "green", "orange", "blue"]
In React, never use .push() or .pop() on state arrays. Instead, use spread to create new arrays: setItems([...items, newItem]). This tells React that the data changed and it needs to re-render.
const user = { name: "Sarah", age: 28, role: "admin" };// Create a new object with one property changedconst updatedUser = { ...user, age: 29 };console.log(user); // { name: "Sarah", age: 28, role: "admin" }console.log(updatedUser); // { name: "Sarah", age: 29, role: "admin" }
This is the pattern you’ll use in React state updates:
Copy
const [user, setUser] = useState({ name: "Sarah", age: 28 });// Update age without mutatingsetUser({ ...user, age: 29 });
Spread creates a shallow copy. If your object contains nested objects, the inner objects are still shared references. For deep nested updates, spread each level: { ...user, address: { ...user.address, city: "Seattle" } }.
Python mental model: this is the same behavior as dict.copy() or {**user} — nested dicts/lists are still shared unless you copy those nested levels too.
The ...(condition && { props }) pattern conditionally includes properties. If the condition is false, false is spread (which adds nothing). You’ll see this when building request bodies with optional fields.
Python mental model: this is similar to {**base, **({"role": "admin"} if is_admin else {})}.