Chapter 4 of 4
When Not to Use an Effect
The four cases where an effect is the wrong tool, and what to do instead.
Most effect bugs come from using an effect for something that is not a side effect at all. Here are the patterns worth un-learning.
1. Deriving data
// Unnecessary: an extra render and a value that can go stale
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(first + " " + last);
}, [first, last]);
// Just calculate it
const fullName = first + " " + last;2. Responding to a user event
// Wrong: the effect cannot tell why the state changed
useEffect(() => {
if (isSubmitted) sendAnalytics("form_submitted");
}, [isSubmitted]);
// Right: do it where the event happens
function handleSubmit() {
sendAnalytics("form_submitted");
setIsSubmitted(true);
}3. Resetting state when a prop changes
// Works, but renders once with the wrong data first
useEffect(() => { setDraft(""); }, [userId]);
// Better: a changing key remounts with fresh state
<ProfileEditor key={userId} userId={userId} />4. Chains of effects
An effect that sets state which triggers another effect that sets more state produces a cascade of renders that is very hard to follow. Compute what you can in one place, and use an event handler for the rest.
Write a cleanup-safe subscribe function
Complete subscribe so it registers the listener and returns a function that removes it again.