Chapter 1 · Practice 2 of 5
Never define a component inside another component
Why it matters
Declaring a component function inside another component creates a brand new component type on every render. React unmounts the old one and mounts the new one, which:
- throws away its state and resets inputs,
- loses focus,
- runs its effects again.
The bug often shows up as an input that loses focus after every keystroke.
Rule: declare every component at the top level of a module. If the inner component needs values from the outer one, pass them as props. This also makes the component easier to test and lets React Compiler optimize it.
Wrapping the inner function in useCallback or the parent in React.memo does not fix this. Only moving the component to module scope does.
Do
- Declare components at module scope and pass data through props
Avoid
- Writing
function Row() {}inside the body of a list component
Example
// Bad: Row is a new type on every render
function List({ items }: { items: string[] }) {
function Row({ text }: { text: string }) {
return <li>{text}</li>;
}
return <ul>{items.map((t) => <Row key={t} text={t} />)}</ul>;
}
// Good: Row lives at the top level
function Row({ text }: { text: string }) {
return <li>{text}</li>;
}