# Updating Objects and Arrays Immutably — React

Source: https://www.skillbyai.com/en/react/s-immutable

> Make new copies, do not mutate.

## React compares references

React decides whether state changed by comparing the old and new values with `Object.is`. If you **mutate** an array or object and pass the same reference to the setter, React sees no change and may skip the re-render, leaving the UI stale. Create **new** arrays and objects instead: spread (`[...items, x]`, `{...user, name}`), `map`, `filter`, `toSorted`. Libraries like Immer let you write mutating-style code that produces copies.

## Mutating versus copying state, run

I ran this with React 19.3 and react-dom 19.3 on Node.js 22, compiling JSX with esbuild 0.28. Browser-style examples use jsdom 29 as a fake DOM (imported from a small setup-dom.mjs file) and act() to apply updates. Pushing into the existing array and calling setItems with the same reference does not update the screen (still 1 item). Setting a new array afterwards re-renders, and the output now shows 3 items, including the one that was pushed earlier: hidden mutation creates confusing bugs.

```jsx
import "./setup-dom.mjs";   // test setup: jsdom provides a browser-like DOM in Node
import { useState, act } from "react";
import { createRoot } from "react-dom/client";

function Todos() {
  const [items, setItems] = useState(["buy milk"]);
  return (
    <>
      <button id="mutate" onClick={() => { items.push("call mom"); setItems(items); }}>mutate</button>
      <button id="copy" onClick={() => setItems([...items, "pay bill"])}>copy</button>
      <p>{items.length} items: {items.join(", ")}</p>
    </>
  );
}
const root = createRoot(document.getElementById("root"));
await act(() => root.render(<Todos />));
await act(() => document.getElementById("mutate").click());
console.log("after mutating:", document.querySelector("p").textContent);
await act(() => document.getElementById("copy").click());
console.log("after copying :", document.querySelector("p").textContent);
```

Output:

```
after mutating: 1 items: buy milk
after copying : 3 items: buy milk, call mom, pay bill
```

## Treat state as read-only

Never call push, splice, sort or assign properties on state; produce a new value and set it.

**Quiz:** Why might mutating a state array not update the screen?

- [ ] React forbids arrays
- [ ] Arrays cannot be state
- [x] The reference is unchanged, so React sees no change
- [ ] Mutation is too fast

*Answer:* The reference is unchanged, so React sees no change. New references signal changes.
