React Core Best Practices
Comprehensive React development guidelines with Vercel optimization patterns.
Instructions
- Component Structure
// ✅ Max 200 lines per component // ✅ Single responsibility
interface Props { user: User; onUpdate: (user: User) => void; }
export function UserCard({ user, onUpdate }: Props) { // Hooks first const [isEditing, setIsEditing] = useState(false);
// Derived state (no useState needed)
const fullName = ${user.firstName} ${user.lastName};
// Event handlers const handleSubmit = () => { ... };
// Render return ( <div className="user-card"> <h2>{fullName}</h2> ... </div> ); }
- Derived State (No useState)
// ❌ Bad - unnecessary state
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(${firstName} ${lastName});
}, [firstName, lastName]);
// ✅ Good - derived state
const fullName = ${firstName} ${lastName};
// ✅ Good - expensive computation const sortedItems = useMemo( () => items.sort((a, b) => a.name.localeCompare(b.name)), [items] );
- Functional setState
// ❌ Bad - stale state risk setCount(count + 1);
// ✅ Good - always current setCount(prev => prev + 1);
// ✅ Good - object state setUser(prev => ({ ...prev, name: newName }));
- Prevent Unnecessary Re-renders
// ✅ Primitive dependencies for useMemo const result = useMemo(() => { return expensiveCalculation(id); }, [id]); // id is primitive
// ✅ Stable callback references const handleClick = useCallback(() => { doSomething(id); }, [id]);
// ✅ Memoize child components const MemoizedChild = memo(ChildComponent);
- Event Handlers
// ❌ Bad - creates new function each render <button onClick={() => handleClick(item.id)}>
// ✅ Good - stable reference with data attribute <button data-id={item.id} onClick={handleClick}>
function handleClick(e: React.MouseEvent<HTMLButtonElement>) { const id = e.currentTarget.dataset.id; // ... }
- Custom Hooks
// ✅ Extract reusable logic function useLocalStorage<T>(key: string, initialValue: T) { const [value, setValue] = useState<T>(() => { const stored = localStorage.getItem(key); return stored ? JSON.parse(stored) : initialValue; });
useEffect(() => { localStorage.setItem(key, JSON.stringify(value)); }, [key, value]);
return [value, setValue] as const; }
- Props Pattern
// ✅ Destructure props
function Button({ children, variant = 'primary', ...rest }: ButtonProps) {
return (
<button className={btn-${variant}} {...rest}>
{children}
</button>
);
}
- Loading & Error States
function UserProfile({ userId }: Props) { const { data, isLoading, error } = useUser(userId);
if (isLoading) return <Skeleton />; if (error) return <ErrorMessage error={error} />; if (!data) return <NotFound />;
return <UserCard user={data} />; }
References
-
React Documentation
-
React TypeScript Cheatsheet