You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
✅ Return objects for multiple values, arrays for ordered pairs
✅ Keep hooks focused on a single concern
✅ Co-locate hooks with components when component-specific, or in hooks/ folder when reusable
Hook Rules
✅ Only call hooks at the top level (not in loops, conditions, or nested functions)
✅ Only call hooks from React components or custom hooks
useEffect Best Practices
✅ Avoid unless necessary: Only use useEffect for true side effects (subscriptions, timers, DOM manipulation, API calls)
✅ Prefer alternatives: Use event handlers, callbacks, or derived state instead of useEffect when possible
✅ Clean up subscriptions, timers, and event listeners
✅ Use dependency arrays correctly
✅ Avoid infinite loops by ensuring dependencies are stable
✅ Prefer useCallback and useMemo for stable references
TypeScript
Type Safety
✅ Always define types for props, state, and function parameters
✅ Prefer interface for data structures (User, Product, etc.)
✅ Use type for unions, intersections, and utility types
✅ Use optional attributes when appropriate: interface Props { optional?: string }
✅ Avoid any - use unknown if type is truly unknown
✅ Use type guards for runtime type checking
Type Definitions
// Good - interface for data structuresinterfaceUser{id: string;name: string;email: string;role?: string;// Optional is acceptable}// Good - type for unions and utilitiestypeStatus='idle'|'loading'|'success'|'error';typeUserWithRole=User&{role: string};// Good - interface for component propsinterfaceUserCardProps{user: User;onEdit?: (user: User)=>void;onDelete?: (id: string)=>void;}// AvoidconstComponent=(props: any)=>{}
Performance
Optimization
✅ Use React.memo for expensive components that re-render frequently
✅ Use useMemo for expensive calculations
✅ Use useCallback for functions passed as props to memoized components
✅ Lazy load routes and heavy components: const Component = lazy(() => import('./Component'))
Rendering
✅ Avoid creating objects/functions in render: move to useMemo/useCallback
✅ Keep component tree shallow when possible
✅ Use keys correctly in lists: stable, unique identifiers (prefer IDs over indices)
Code Quality
Naming Conventions
Components: PascalCase (AppBar, UserProfile)
Hooks: camelCase with use prefix (useAuth, useDataFetch)
// Good - inline for simple handlers<buttononClick={()=>handleClick(id)}>Click</button>// Good - extracted for complex logicconsthandleSubmit=useCallback(async(e: React.FormEvent)=>{e.preventDefault();// complex logic},[dependencies]);
Component Composition
// Good - using children<Layout><MainContent/></Layout>// Good - using composition with sub-components<Form><FormSection/><FormActions/></Form>
// Good - extract form logic to hookconst{
formData,
errors,
isSubmitting,
setField,
handleSubmit,}=useForm({ initialData, onSubmit });// Good - use sub-components for form sections<FormSectionformData={formData}errors={errors}onFieldChange={setField}/>
Service Layer Pattern
// services/userService.tsexportconstcreateUser=async(data: UserData): Promise<User>=>{// API operations};exportconstgetUsers=async(): Promise<User[]>=>{// Query logic};
Data Fetching
// Good - custom hook for data fetchingconst{ data, loading, error }=useDataFetch<User[]>(()=>getUsers());// Good - handle loading and error states{loading&&<Spinner/>}{error&&<ErrorMessageerror={error}/>}{data&&<DataListdata={data}/>}
Routing (if applicable)
Route Organization
✅ Use a routing library (React Router, Next.js Router, etc.)
✅ Protect routes with authentication/authorization
✅ Use route-based code splitting
✅ Keep route components in pages/ or routes/ folder
Testing (if applicable)
Testing Best Practices
✅ Write unit tests for utilities and hooks
✅ Write integration tests for components
✅ Test user interactions, not implementation details
✅ Use testing library best practices
Anti-Patterns to Avoid
❌ Mutating state directly
❌ Using array indices as keys (use stable IDs)
❌ Creating components inside render
❌ Ignoring TypeScript errors
❌ Over-optimizing prematurely
❌ Mixing business logic with UI components
❌ Using inline styles when utility classes exist
❌ Not handling loading and error states
❌ Not cleaning up subscriptions and resources
❌ Hardcoding sensitive data or API keys
❌ Forgetting to handle async errors in try/catch blocks
❌ Creating unnecessary re-renders with unstable references
❌ Using useEffect for derived state instead of useMemo