function App() {
const [color, setColor] = useState('red');
return (
<div style={{ color }}>
<input value={color} onChange={e => setColor(e.target.value)} />
<ExpensiveTree />
</div>
);
}
Change the component structure so the state no longer sits above ExpensiveTree.
Move state down. If only the input needed color, extract a small Form component. It owns the state and the input, and renders next to ExpensiveTree. Then typing only re-renders Form.
Lift content up. Here the div also uses color, so moving state down is not enough. Instead, lift the expensive part up: create it in the parent and pass it in as children. Create ColorPicker, which owns the state and renders the div, the input and {children}. App renders <ColorPicker><ExpensiveTree /></ColorPicker>.
Why this works: when ColorPicker updates its state, the children prop is still the same element object. App created it, and App did not re-render. React sees the same element and skips ExpensiveTree.
Try this before reaching for memoization.
- Move state down into the component that uses it.
- Lift content up: pass the expensive part in as
children. childrenwas created by a parent that did not re-render.- The same element reference lets React skip that subtree.
- Fix the structure first, and use memoization second.