--- description: globs: *.tsx alwaysApply: false --- # React ## Core Principles - **Component-Driven Development**: Build applications as a composition of isolated, reusable components - **One-Way Data Flow**: Follow React's unidirectional data flow pattern - **Single Responsibility**: Each component should have a clear, singular purpose - **TypeScript First**: Use TypeScript for type safety and better developer experience - **Internationalization (i18n) By Default**: All user-facing text should be translatable ## React Components ### Component Structure - Always use functional components with TypeScript - Name components using PascalCase (e.g., `UserProfile`) - Use named exports for components, not default exports - Split components by responsibility and avoid "god components" - Name files to match their component name (e.g., `user-profile.tsx`) ### Props - Always type props using TypeScript interfaces or type aliases - Use discriminated unions for complex prop types with conditional rendering - Destructure props at the start of component functions - Use prop spreading cautiously and only when appropriate - Provide default props for optional parameters when it makes sense ```typescript type ButtonProps = { variant: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; children: React.ReactNode; disabled?: boolean; onClick?: () => void; }; function Button({ variant, size = 'md', children, disabled = false, onClick }: ButtonProps) { // Component implementation } ``` ### State Management - Keep state as local as possible - Lift state up when multiple components need access - Use Context sparingly and only for truly global state - Prefer the "Container/Presenter" pattern when separating data and UI ```typescript // Container component (manages data) function UserProfileContainer() { const userData = useUserData(); if (userData.isLoading) { return ; } if (userData.error) { return ; } return ; } // Presenter component (renders UI) function UserProfilePresenter({ data }: { data: UserData }) { return (

{data.name}

{/* Rest of the UI */}
); } ``` ### Hooks - Follow the Rules of Hooks (only call hooks at the top level, only call them from React functions) - Create custom hooks for reusable logic - Keep custom hooks focused on a single concern - Name custom hooks with a 'use' prefix (e.g., `useUserProfile`) - Extract complex effect logic into separate functions - Always provide a complete dependencies array to `useEffect` ### Performance Optimization - Apply `useMemo` for expensive calculations - Use `useCallback` for functions passed as props to child components - Split code using dynamic imports and `React.lazy()` ```typescript const MemoizedComponent = React.memo(function Component(props: Props) { // Component implementation }); // For expensive calculations const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); // For callback functions passed as props const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]); ``` ### Internationalization (i18n) - Always use the `Trans` component for text rendering (no hardcoded strings) - Ensure all i18n keys are available in locale files - Use namespaces to organize translations logically - Include interpolation variables in translation keys - Test UI with different languages, especially those with longer text ```typescript // Correct // Incorrect

Welcome, {user.name}!

``` ## Server Components ### Fundamentals - Server Components render React server-side and never run on the client - Use Server Components as the default choice, especially for data fetching - No use of hooks, browser APIs, or event handlers in Server Components - No use of `useState`, `useEffect`, or any other React hooks - Server Components can render Client Components but not vice versa ### Data Fetching - Fetch data directly using async/await in Server Components - Use Suspense boundaries around data-fetching components - Apply security checks before fetching sensitive data - Never pass sensitive data (API keys, tokens) to Client Components - Use React's `cache()` function for caching data requests ### Error Handling - Implement error boundaries at appropriate levels - Use the Next.js `error.tsx` file for route-level error handling - Create fallback UI for when data fetching fails - Log server errors appropriately without exposing details to clients ### Streaming and Suspense - Use React Suspense for progressive loading experiences if specified - Implement streaming rendering for large or complex pages - Structure components to enable meaningful loading states - Prioritize above-the-fold content when using streaming ## Client Components ### Fundamentals - Add the `'use client'` directive at the top of files for Client Components - Keep Client Components focused on interactivity and browser APIs - Use hooks appropriately following the Rules of Hooks - Implement controlled components for form elements - Handle all browser events in Client Components ### Data Fetching - Use React Query (TanStack Query) for data fetching in Client Components - Create custom hooks for data fetching logic (e.g., `useUserData`) - Always handle loading, success, and error states ### Form Handling - Use libraries like React Hook Form for complex forms - Implement proper validation with libraries like Zod - Create reusable form components - Handle form submissions with loading and error states - Use controlled components for form inputs ### Error Handling - Implement error boundaries to catch and handle component errors if using client components - Always handle network request errors - Provide user-friendly error messages - Log errors appropriately - Implement retry mechanisms where applicable ```typescript 'use client'; import { ErrorBoundary } from 'react-error-boundary'; function ErrorFallback({ error, resetErrorBoundary }) { return (

Something went wrong:

{error.message}
); } export function UserProfileWithErrorHandling() { return ( { // Reset application state here if needed }} > ); } ```