React Best Practices
Conventions keep codebases consistent and maintainable. Follow these patterns to write clean React code.
File Structure
Organize by feature, not by type.
src/
features/
auth/
LoginForm.jsx
useAuth.js
authSlice.js
dashboard/
Dashboard.jsx
StatsCard.jsx
Avoid putting all components in one folder as the app grows.
Naming Conventions
- Components: PascalCase —
UserProfile.jsx - Hooks: camelCase with
useprefix —useAuth.js - Utils: camelCase —
formatDate.js - Constants: UPPER_SNAKE_CASE —
MAX_RETRIES - Files: match the default export name
Keep Components Small
Each component should do one thing.
// BAD: One giant component
function Dashboard() {
// 200 lines of mixed logic
}
// GOOD: Split into focused components
function Dashboard() {
return (
<Layout>
<Header />
<StatsPanel />
<ActivityFeed />
</Layout>
);
}
State Placement
- Local state: UI state like open/closed, form inputs, hover effects
- Lifted state: shared between siblings
- Global state: truly app-wide (auth, theme, cart)
Don’t use global state for everything. Start local, lift when needed.
Inline Logic
Avoid complex logic inside JSX.
// BAD
<div>{users.filter(u => u.active).map(u => <span>{u.name.toUpperCase()}</span>)}</div>
// GOOD
const activeUsers = users.filter((u) => u.active);
return <div>{activeUsers.map((u) => <UserRow key={u.id} user={u} />)}</div>;
Common Pitfalls Checklist
- Using
indexaskeyfor dynamic lists - Mutating state directly instead of creating new references
- Putting too much in a single component
- Not extracting reusable logic into custom hooks
- Inline object/array literals in JSX causing unnecessary re-renders
- Forgetting to handle loading and error states
- Mixing concerns (data fetching + presentation) in one component
Best Practices
- One component per file
- Extract custom hooks for reusable logic
- Use TypeScript for prop validation
- Keep JSX clean — move logic above the return
- Handle all states: loading, error, empty, success
- Use
keywith stable, unique identifiers
Common Mistakes
- Over-abstracting too early — keep it simple until patterns emerge
- Creating deeply nested component trees
- Passing too many props (split the component instead)
- Ignoring the component hierarchy when deciding state placement
- Not using dev tools to check render frequency