Give the component a key tied to its subject. When the key changes, React unmounts the old instance and mounts a new one, so every useState inside starts fresh.
<Editor key={docId} doc={doc} />
Switch from document 12 to document 13 and the editor’s draft text, its dirty flag and its scroll position all reset, with no code inside Editor knowing about it.
The alternative, and why it loses
The other option is an effect that watches the prop and resets state by hand:
useEffect(() => {
setDraft(doc.body);
setDirty(false);
}, [doc.id]);
That renders once with stale state, then again with the reset, and it has to name every piece of state. Add a new useState next year and forget to add it here, and the bug is back. The key does all of it in one render.
When a key is the wrong tool
- The state should survive. A filter panel that must keep its settings across selected items has no business resetting; pass the item in as a prop and leave the key alone.
- The component is expensive to mount. A key remounts the whole subtree, including children, refs and their effects. Most editors and forms are cheap enough that this doesn’t matter.
Gotchas
- Keys only need to be unique among siblings.
key={docId}on one child is fine even if a sibling uses the same value. - Changing the key also drops DOM focus. If the user is mid-typing when the subject changes, that’s usually right; if not, refocus in an effect on the new instance.
- Don’t key on something that changes every render, like a fresh object. The component remounts each time and looks like a flicker.