Chapter 2 of 4
The Dependency Array
The three forms of the second argument and what each one means.
The second argument controls when the effect re-runs. React compares each dependency with its value from the previous render using Object.is.
// No array: runs after every single render
useEffect(() => { /* ... */ });
// Empty array: runs once, after the first render
useEffect(() => { /* ... */ }, []);
// With dependencies: runs when any of them changes
useEffect(() => { /* ... */ }, [userId, filter]);Every reactive value belongs in the array
If the effect body reads a prop, a state value, or anything derived from them, it must be listed. Leaving something out gives you an effect that keeps using a stale value from an old render.
function Chat({ roomId }) {
useEffect(() => {
const connection = connect(roomId);
return () => connection.close();
}, [roomId]); // reconnects when the room changes
// With [] it would connect to the first room forever
}Objects and functions as dependencies
A new object or function is created on every render, so it never equals the previous one and the effect runs every time. Move it inside the effect, or memoise it.
// Runs on every render: options is a new object each time
const options = { limit: 10 };
useEffect(() => { load(options); }, [options]);
// Fix 1: move it inside
useEffect(() => {
load({ limit: 10 });
}, []);
// Fix 2: depend on the primitive value
useEffect(() => {
load({ limit });
}, [limit]);An empty array is a claim
[] says 'nothing this effect uses will ever change'. That is true for a one-off subscription to window, and usually false for anything involving props.