Group related components under a shared parent that manages state.
<Select>
<Select.Option value="a">Option A</Select.Option>
<Select.Option value="b">Option B</Select.Option>
</Select>Pass a function as a prop to share stateful logic.
<Mouse render={({ x, y }) => <Cursor x={x} y={y} />} />Extract and share stateful logic without wrapping components.
function useWindowSize() {
const [size, setSize] = useState({ w: 0, h: 0 });
useEffect(() => {
const update = () => setSize({ w: window.innerWidth, h: window.innerHeight });
window.addEventListener('resize', update);
return () => window.removeEventListener('resize', update);
}, []);
return size;
}When siblings need to share state, lift it to their nearest common parent.
const StateContext = createContext();
function StateProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
return <StateContext.Provider value={{ state, dispatch }}>{children}</StateContext.Provider>;
}Compute values from existing state instead of duplicating state.
// Bad — duplicated state
const [items, setItems] = useState([]);
const [count, setCount] = useState(0);
// Good — derived
const [items, setItems] = useState([]);
const count = items.length;| Pattern | Hook/API | Use When |
|---|---|---|
| Skip re-renders | React.memo |
Child rerenders with same props |
| Cache expensive value | useMemo |
Heavy computation on every render |
| Stable function reference | useCallback |
Passing callbacks to memoized children |
| Defer non-urgent updates | useTransition |
Keeping UI responsive during slow updates |
| Lazy load components | React.lazy + Suspense |
Code splitting by route/feature |
Use a library (React Query, SWR) over raw useEffect for:
- Automatic caching and deduplication
- Loading/error states out of the box
- Background refetching and stale-while-revalidate
- Optimistic updates
const { data, isLoading, error } = useQuery({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
});