Common mistakes
Using the updater's argument without the arrow
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<button onClick={() => setNumber(n + 1)}>{number}</button>
);
}
// Act like a user: click once.
setTimeout(() => document.querySelector('button').click(), 50);
What React prints
ReferenceError: n is not defined
Why, and the fix
n exists only as the parameter of an updater function. Without n =>, setNumber(n + 1) reads a variable n that nobody declared, so the click throws an uncaught ReferenceError and nothing changes. Write the updater in full: setNumber(n => n + 1).
Returning the result of push from an updater
import { useState } from 'react';
export default function Tags() {
const [tags, setTags] = useState(['react']);
return (
<>
<ul>
{tags.map(tag => <li key={tag}>{tag}</li>)}
</ul>
<button onClick={() => setTags(t => t.push('state'))}>Add</button>
</>
);
}
// Act like a user: click once.
setTimeout(() => document.querySelector('button').click(), 50);
What React prints
TypeError: tags.map is not a function
Why, and the fix
An updater must return the next state. push changes the array in place and returns its new length, a number, so tags becomes a number and the render throws (Chrome and Node wording; Firefox and Safari word it differently). Changing the array is impure too, and Strict Mode runs the updater twice. Return a new array: setTags(t => [...t, 'state']).
Forgetting return in an updater with braces
import { useState } from 'react';
export default function Tags() {
const [tags, setTags] = useState(['react']);
return (
<>
<ul>
{tags.map(tag => <li key={tag}>{tag}</li>)}
</ul>
<button onClick={() => setTags(t => { [...t, 'state']; })}>Add</button>
</>
);
}
// Act like a user: click once.
setTimeout(() => document.querySelector('button').click(), 50);
What React prints
TypeError: Cannot read properties of undefined (reading 'map')
Why, and the fix
With braces, an arrow function needs return; without it, the updater returns undefined, which becomes the next state, and the render throws (Chrome and Node wording; Firefox and Safari word it differently). Drop the braces, t => [...t, 'state'], or write t => { return [...t, 'state']; }.
React in the browser: React 19.3.0 (development build) and React Testing Library, MIT, served from this site; JSX is compiled by TypeScript 6.0.3, Apache-2.0. Licence and source