Explain Codes LogoExplain Codes Logo

Why is useState not triggering re-render?

javascript
react-state-management
functional-updates
immutability
Alex KataevbyAlex Kataev·Mar 13, 2025
TLDR

To induce a re-render with useState, consistently update the state with a new reference. React avoids re-rendering when encountering identical references. For objects or arrays, the spread syntax generates a new reference:

const [state, setState] = useState({ day: 'Monday' }); // Correct: Use spread to update state with a new object reference setState(prevState => ({ ...prevState, day: 'Sunday yet?' }));

Always remember: setting state identical to the previous reference will not trigger a re-render. Doctor JavaScript doesn't see equal twins as two different people, okay?

State Fear Factor: Mutations & Updates

Immutability is the pole star for state updates. Direct mutations might not only confuse Mr. React but also lead to ghost-like bugs because React considers reference comparison for changes. Return a new object or array while updating state, one which React would recognize:

For arrays🔵 🔵 🔵:

const [numbers, setNumbers] = useState([1, 2, 3]); // This is how IronMan adds his new suits... setNumbers(oldNumbers => [...oldNumbers, 4]);

For objects 🔲 🔲 🔲:

const [user, setUser] = useState({ name: 'Bruce' }); // This is how Bruce Banner turns into the Incredible Hulk! setUser(oldUser => ({ ...oldUser, name: 'Hulk' }));

This guarantees a fresh reference, one that React can't resist rerendering.

The Chess of Functional Updates

If your new state uses previous state as a steppingstone, a functional update serves as a knight's move. It trashes stale closures & fetches the latest state value:

const [count, setCount] = useState(0); // This is incrementing count like Pikachu charges Thunderbolt! setCount(prevCount => prevCount + 1);

Beautiful in event handlers or effects where previous state might prove as outdated as Windows '98!

Beware of These Traps

Don't Hulk-Smash state directly

Beware, direct mutations like numbers[2] = 99 or user.name = Thor are not honored by the Asgard of React. Use the setState function artistically with a new array or object instead.

useEffect is not a lone wolf

Coupling useState & useEffect are like Batman & Robin; a dependency array is their batmobile:

useEffect(() => { // A beautiful arc reactor absolutely depending on `state` }, [state]); // State served on a silver platter!

No fake ID's in the List Club

Rendering lists? Always throw unique keys to list items through the door. React holds keys to identify changed, added, or removed rats:

numbers.map((number, index) => ( // Guest checked-in with a unique ID. Don't accept duplicates, we're not Matrix invitees! <li key={index}>{number}</li> ));

Upgrade Your Arsenal: Advanced Patton's

Meet the Commander-in-Chief: useReducer

Waging with complex state? Call useReducer. Actions and a reducer function govern updates.

The Secret Agent: Derived state

Sometimes, you run undercover operations, so you derive state from props or state agents. useMemo maintains your cover:

// This here is a secret weapon, don't show it around too much... const derivedValue = useMemo(() => expensiveComputation(sourceValue), [sourceValue]);

Higher the rank, better the vision: Lifting state up

Sharing state makes your components perform in coherence like a marching choir. Lift the state up to clear the fog among communing components.