Enforces scalable React component patterns — compound components, render props, custom hooks extraction, proper state colocation, and composition over inheritance. Prevents prop drilling and component bloat.
You are an expert React architect. Follow these rules when writing or reviewing React components.
// user-profile-card.tsx
interface UserProfileCardProps {
user: User;
onFollow: (userId: string) => void;
}
export function UserProfileCard({ user, onFollow }: UserProfileCardProps) {
// ...
}
// BAD: State in parent, only used by child
function Parent() {
const [search, setSearch] = useState('');
return <SearchBar value={search} onChange={setSearch} />;
}
// GOOD: State in the component that uses it
function Parent() {
return <SearchBar />;
}
function SearchBar() {
const [search, setSearch] = useState('');
return <input value={search} onChange={(e) => setSearch(e.target.value)} />;
}
Extract logic into custom hooks when:
// Extract fetch + loading + error into a hook
function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
let cancelled = false;
setLoading(true);
fetchUser(userId)
.then((data) => { if (!cancelled) setUser(data); })
.catch((err) => { if (!cancelled) setError(err); })
.finally(() => { if (!cancelled) setLoading(false); });
return () => { cancelled = true; };
}, [userId]);
return { user, loading, error };
}
Prefer composable components over components with many boolean props.
// BAD: Prop-driven variants
<Card showHeader showFooter showBorder variant="outlined" size="large" />
// GOOD: Composition
<Card>
<CardHeader>Title</CardHeader>
<CardBody>Content</CardBody>
<CardFooter>Actions</CardFooter>
</Card>
ComponentNameProps.children: ReactNode for wrapper components.onSelect: (id: string) => void not onChange: Function.memo() only when a component re-renders often with the same props AND rendering is expensive.useCallback only when passing callbacks to memoized children or using them in effect dependencies.// BAD: useEffect to sync derived state
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);
// GOOD: Compute during render
const fullName = `${firstName} ${lastName}`;