Concept
SOLID Principles on the Frontend
Frontend applications benefit from SOLID principles just as backend architectures do:
- Single Responsibility Principle (SRP): A component should have one reason to change. Separate data fetching (Container/Hook) from rendering (Presentational component).
- Open/Closed Principle (OCP): Software entities should be open for extension, but closed for modification. Implement polymorphic render props or polymorphic components.
- Liskov Substitution Principle (LSP): A sub-class or extension should be drop-in replaceable with its parent. Custom wrapper components must match standard HTML element attributes.
- Interface Segregation Principle (ISP): Components should not depend on interfaces they do not use. Don't pass a massive
userobject to a component that only needsuser.avatarUrl. - Dependency Inversion Principle (DIP): High-level modules should not depend on low-level modules; both should depend on abstractions. Inject API clients instead of hardcoding raw axios/fetch instances.
Layers of Clean Architecture on the Frontend
Clean Architecture segregates code into concentric rings:
┌─────────────────────────────────────────┐
│ Frameworks & Drivers (React, UI, API) │
│ ┌───────────────────────────────┐ │
│ │ Adapters (Mappers, Present) │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ Use Cases (Rules) │ │ │
│ │ │ ┌───────────┐ │ │ │
│ │ │ │ Entities │ │ │ │
│ │ │ └───────────┘ │ │ │
│ │ └─────────────────────┘ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────────┘- Entities: Core business objects and interfaces (e.g.,
User,Cart,Product). They know nothing about React, Next.js, or local storage. - Use Cases: Application-specific business rules. Functions that manipulate entities (e.g.,
calculateCartTotal,validatePromoCode). - Interface Adapters: Translators between the core logic and the UI framework. This includes custom hooks, selectors, and API payload formatters/mappers.
- Frameworks & Drivers: The outer ring. React components, browser DOM, Next.js routes, CSS modules.
Common Mistakes
1. Inlining business calculations inside component renders
Putting equations or filter arrays inside JSX blocks causes performance re-renders and couples logic to UI. Move calculations to standalone helper utilities or custom hooks.
2. Leaking API shapes into form inputs
Directly binding a form element to a raw database/API payload shape makes the UI fragile. If the backend changes its key structure, the frontend form breaks. Always map payloads to entities before they reach the UI.
Best Practices
- Write framework-agnostic core logic: You should be able to unit-test your core business rules without mounting React trees or importing
@testing-library/react. - Use Dependency Injection: Pass APIs, local storage interfaces, and logging boundaries as dependencies to hooks or classes to make mock testing trivial.
- Implement Adapter Mappers: Explicitly translate API payloads (snake_case) to frontend models (camelCase) at the network layer boundary.
