Skip to content

bablukpik/nextjs-best-practices

Repository files navigation

Next.js Best Practices Guide

This project demonstrates common problems and their solutions using modern React/Next.js patterns.

How to navigate the project

  • The homepage groups each problem with its relevant solutions for quick discovery.
  • Each problem page lists all of its solution approaches with links.
  • Each solution page links back to the original problem and to alternative solutions.

Example: Problem 1 — "Too Many Boolean Props"

Compare four different solution approaches side-by-side:

  • Solution 1: Variant Pattern — /problems/problem-2
  • Solution 2: Composition Pattern — /problems/problem-3
  • Solution 3: Config Object — /problems/problem-4
  • Solution 4: Compound Components — /problems/problem-5

6 Core Design Patterns Used Throughout

All solutions in this project apply these 6 fundamental patterns:

1. Specialized Component Extraction

Breaking down large components into smaller, focused pieces that handle one responsibility.

2. Compound Components Pattern

Creating a parent component with sub-components that work together, allowing flexible composition.

3. Grouping Related Props into Configuration Objects

Instead of spreading props everywhere, group related props into logical config objects.

4. Component Composition

Building complex UIs by composing smaller, reusable components rather than using conditional props.

5. Separation of Concerns

Each component should have a single, well-defined responsibility.

6. Slots Pattern

Using named slots (sub-components) to allow flexible content placement while maintaining structure.


Problems Demonstrated

Problem 1: Too Many Boolean Props

Patterns Applied: ✅ Specialized Components, ✅ Compound Components, ✅ Config Objects, ✅ Composition, ✅ Separation of Concerns, ✅ Slots

Components with 15+ boolean props to handle different states and variations.

Solution: Variant Pattern + Composition + Config Objects

How Patterns Are Applied:

  • Specialized Components: Separate Header, Content, Footer, StateMessage components
  • Compound Components: Form.Header, Form.Content, Form.Footer sub-components
  • Config Objects: Group display, state, and style props into config object
  • Composition: Use children and slots instead of conditional rendering
  • Separation of Concerns: Each component handles one responsibility
  • Slots Pattern: Named slots for flexible content placement

Problem 2: Variant Pattern Solution

Patterns Applied: ✅ Specialized Components, ✅ Config Objects, ✅ Composition, ✅ Separation of Concerns

Uses a single variant prop instead of multiple booleans.

How Patterns Are Applied:

  • Specialized Components: Separate components for each variant
  • Config Objects: Variant config groups related styling
  • Composition: Compose variant-specific sub-components
  • Separation of Concerns: Each variant has its own component

Problem 3: Composition Pattern Solution

Patterns Applied: ✅ Specialized Components, ✅ Compound Components, ✅ Composition, ✅ Separation of Concerns, ✅ Slots

Breaks components into smaller, composable pieces.

How Patterns Are Applied:

  • Specialized Components: FormHeader, FormContent, FormFooter
  • Compound Components: Form.* sub-components
  • Composition: Build complex forms from simple pieces
  • Separation of Concerns: Each piece has one job
  • Slots Pattern: Named slots for content

Problem 4: Config Object Solution

Patterns Applied: ✅ Config Objects, ✅ Specialized Components, ✅ Separation of Concerns

Groups related props into a single configuration object.

How Patterns Are Applied:

  • Config Objects: All props grouped into config
  • Specialized Components: Config determines which components render
  • Separation of Concerns: Config handles all concerns

Problem 5: Compound Components Solution

Patterns Applied: ✅ Compound Components, ✅ Specialized Components, ✅ Slots, ✅ Composition, ✅ Separation of Concerns

Uses the compound component pattern for maximum flexibility.

How Patterns Are Applied:

  • Compound Components: Parent with multiple sub-components
  • Specialized Components: Each sub-component is specialized
  • Slots Pattern: Sub-components act as named slots
  • Composition: Flexible arrangement of sub-components
  • Separation of Concerns: Each sub-component has one role

Problem 2: Prop Drilling

Patterns Applied: ✅ Composition, ✅ Separation of Concerns

Passing props through multiple levels of components that don't use them.

Solution: Context API + Custom Hooks + Composition

How Patterns Are Applied:

  • Composition: Use Context to avoid prop drilling
  • Separation of Concerns: Context handles data flow separately

Problem 3: Conflicting Props

Patterns Applied: ✅ Config Objects, ✅ Separation of Concerns

Props that create invalid combinations (e.g., disabled={true} + required={true}).

Solution: Discriminated Unions + Type Safety

How Patterns Are Applied:

  • Config Objects: State config prevents conflicts
  • Separation of Concerns: Each state is mutually exclusive

Problem 4: Callback Hell

Patterns Applied: ✅ Config Objects, ✅ Composition, ✅ Separation of Concerns

Too many callback/handler props cluttering the component.

Solution: Event Object Pattern + Custom Hooks

How Patterns Are Applied:

  • Config Objects: Group callbacks into event object
  • Composition: Use custom hooks for logic
  • Separation of Concerns: Handlers separated from UI

Problem 5: Spread Props Anti-pattern

Patterns Applied: ✅ Specialized Components, ✅ Separation of Concerns

Spreading unknown props without control, creating hidden dependencies.

Solution: Explicit Prop Forwarding + Prop Whitelisting

How Patterns Are Applied:

  • Specialized Components: Each component explicitly defines props
  • Separation of Concerns: Clear prop boundaries

Problem 6: State vs Props Confusion

Patterns Applied: ✅ Composition, ✅ Separation of Concerns

Props that should be internal component state.

Solution: Controlled vs Uncontrolled Pattern + Custom Hooks

How Patterns Are Applied:

  • Composition: Use custom hooks for state logic
  • Separation of Concerns: State management separated from UI

Problem 7: Prop Coupling

Patterns Applied: ✅ Config Objects, ✅ Specialized Components, ✅ Separation of Concerns

Props that must be used together or depend on each other.

Solution: Group Related Props + Config Objects

How Patterns Are Applied:

  • Config Objects: Related props grouped together
  • Specialized Components: Each config type has its component
  • Separation of Concerns: Each concern is independent

Problem 8: Type Safety Issues

Patterns Applied: ✅ Config Objects, ✅ Separation of Concerns

Weak typing that allows invalid prop values at compile time.

Solution: Strict TypeScript Types + Zod Validation

How Patterns Are Applied:

  • Config Objects: Type-safe config objects
  • Separation of Concerns: Validation separated from logic

Problem 9: Server Actions vs Client Handlers

Patterns Applied: ✅ Composition, ✅ Separation of Concerns

Mixing server actions with client handlers creates confusion.

Solution: Clear separation between server and client logic

How Patterns Are Applied:

  • Composition: Server actions in separate layer
  • Separation of Concerns: Server logic separate from client UI

Problem 10: Hook Prop Drilling

Patterns Applied: ✅ Composition, ✅ Separation of Concerns

Passing hook results through props instead of using hooks directly.

Solution: Custom Hooks + Composition

How Patterns Are Applied:

  • Composition: Use custom hooks directly in components
  • Separation of Concerns: Logic in hooks, UI in components

Problem 11: Async Props

Patterns Applied: ✅ Composition, ✅ Separation of Concerns

Handling async data in props is problematic.

Solution: Server Components + Async/Await

How Patterns Are Applied:

  • Composition: Async logic in Server Components
  • Separation of Concerns: Data fetching separate from rendering

Problem 12: Custom Hooks Over Props

Patterns Applied: ✅ Composition, ✅ Separation of Concerns

Extracting logic into custom hooks instead of passing callbacks.

Solution: Custom Hooks + Composition

How Patterns Are Applied:

  • Composition: Logic extracted to reusable hooks
  • Separation of Concerns: Logic separate from UI

Pattern Application Matrix

Problem Specialized Compound Config Composition Separation Slots
1. Too Many Props
2. Variant Pattern
3. Composition
4. Config Objects
5. Compound Components
6. Prop Drilling
7. Conflicting Props
8. Callback Hell
9. Spread Props
10. State vs Props
11. Prop Coupling
12. Type Safety
13. Server Actions
14. Hook Drilling
15. Async Props
16. Custom Hooks

Best Practice Recommendations

Universal Best Practices

  1. Always use TypeScript - Catch errors at compile time
  2. Group related props - Use config objects or compound components
  3. Avoid prop drilling - Use Context API or custom hooks
  4. Be explicit - Don't spread unknown props
  5. Separate concerns - Use composition to break down complexity
  6. Document prop relationships - Use types to make dependencies clear
  7. Validate at boundaries - Use Zod or similar for runtime validation
  8. Test prop combinations - Ensure only valid combinations work

Implementation Priority

  1. Start with TypeScript - Strict types prevent most issues
  2. Use Composition - Break components into smaller pieces
  3. Add Variants - Define clear states
  4. Group Props - Use config objects for related props
  5. Use Context - Only when necessary to avoid prop drilling
  6. Validate - Add Zod validation for complex props

Conclusion

All solutions in this project demonstrate how to apply the 6 core design patterns to solve real-world component prop problems. The key is understanding which patterns to apply for each specific problem:

  • Composition + Variants is the most flexible and maintainable for most cases
  • Strict TypeScript should always be used
  • Context API should be used sparingly for deeply nested data
  • Config Objects should group related props
  • Discriminated Unions should prevent invalid combinations
  • Specialized Components should handle single responsibilities
  • Compound Components should provide maximum flexibility
  • Slots Pattern should enable content customization

Start with these principles and adjust based on your component's complexity and use cases.

Releases

No releases published

Packages

No packages published