One rule
Use useEffect only to synchronize your component with something outside React. Examples: browser storage, a timer, a map widget, a chat connection, or a non-React library.
If you are only calculating a value from props or state, do it during render. If you are responding to a click or form submit, do it in the event handler.
What counts external
React already handles rendering from state and props. Your app does not need an effect to keep two React values in sync. That usually creates duplicate state and bugs.
An external system is something React does not control. localStorage is outside React. document.title is outside React. A server connection is outside React.
Common wrong effect
Beginners often store a filtered list in state, then use an effect to update it when the search text changes. That is not needed.
The filtered list can be computed from the current list and search text during render. Less state means fewer bugs.
function ProjectList({ projects, search }) {
const visibleProjects = projects.filter((project) =>
project.name.toLowerCase().includes(search.toLowerCase())
);
return (
<ul>
{visibleProjects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
);
}Useful effect
This effect is justified because document.title belongs to the browser, not React. The dependency list includes the value used inside the effect.
Call Hooks at the top level of your component. Do not put useEffect inside an if block, loop, or nested function.
import { useEffect, useState } from 'react';
export default function App() {
const [projects, setProjects] = useState([]);
const [name, setName] = useState('');
useEffect(() => {
document.title = `${projects.length} projects saved`;
}, [projects.length]);
function addProject(event) {
event.preventDefault();
const trimmedName = name.trim();
if (!trimmedName) return;
setProjects([
...projects,
{ id: crypto.randomUUID(), name: trimmedName }
]);
setName('');
}
return (
<form onSubmit={addProject}>
<input
value={name}
onChange={(event) => setName(event.target.value)}
placeholder="Project name"
/>
<button>Add project</button>
</form>
);
}Effect checklist
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done
Use AI carefully
You can ask an AI tool to review your component: “Find useEffect calls that can be removed. Explain why.” Do not accept the answer blindly.
Check three things yourself: is there an external system, are dependencies complete, and can the value be computed during render instead.
Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done