React Patterns & Best Practices
Component Structure
- Use functional components with hooks
- Keep components small and focused (single responsibility)
- Extract custom hooks for reusable logic
- Co-locate related files (component, styles, tests)
State Management
Local State
const [value, setValue] = useState(initialValue);
Complex State
const [state, dispatch] = useReducer(reducer, initialState);
Global State Options
- React Context for simple global state (auth, theme)
- Zustand for lightweight state management
- Jotai for atomic state
- Redux Toolkit for complex applications
Hooks Patterns
Custom Hooks
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
Data Fetching
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
Performance Optimization
Memoization
// Memoize expensive calculations
const expensiveValue = useMemo(() => computeExpensive(a, b), [a, b]);
// Memoize callbacks
const handleClick = useCallback(() => doSomething(id), [id]);
// Memoize components
const MemoizedComponent = React.memo(MyComponent);
Lazy Loading
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
Component Patterns
Compound Components
<Select>
<Select.Option value="a">Option A</Select.Option>
<Select.Option value="b">Option B</Select.Option>
</Select>
Render Props
<DataFetcher url="/api/data">
{({ data, loading }) => loading ? <Spinner /> : <List items={data} />}
</DataFetcher>
Higher-Order Components
const withAuth = (Component) => (props) => {
const { user } = useAuth();
if (!user) return <Redirect to="/login" />;
return <Component {...props} user={user} />;
};