React provides a great deal of flexibility, but along with this freedom, comes the responsibility of designing your own architecture. It's crucial to be intentional about how you structure your applications to ensure they are user-friendly, comprehensible, and amenable to future extensions. There are established architectural methodologies that can significantly enhance the organization of your React project. I'll now guide you on how to incorporate one of these methodologies into your React folder structure.
- Clean Architecture
- Vertical Slice Architecture
- Feature-sliced design (FSD)
Traditional Approach with Clean Architecture
In the traditional Clean Architecture approach applied to a React application, the concerns are structured into distinct layers, each with its specific responsibility and clear boundaries. This separation of concerns enables a well-organized and maintainable code base.
Suggested Folders Structure in React:
Components: This layer corresponds to the UI components in React. It handles user interactions and rendering of the application. It may reference the Container layer and the Core layer as needed.
Containers: This layer is responsible for implementing the application logic. It contains components that are connected to the state (using Redux or Context API) and handle data fetching and manipulation. It may reference the Core layer for domain-specific logic.
Services: This layer is akin to the Application layer in Clean Architecture. It implements use cases, and application services, and manages contracts such as API endpoints, data fetching, and external services. It may reference the Core layer for domain logic.
Utilities: This layer is similar to the Infrastructure layer. It handles low-level concerns like network requests, local storage, and other external dependencies. It may have references to both the Core and Services layers.
Core: This layer is responsible for the business logic and rules. It ensures that the domain model is always valid and handles core functionality. It has no dependencies on other layers.
Example Folder Structure:
src/
|-- Components/
| |-- Header/
| | |-- Header.js
| | |-- Header.css
| |-- ...
|
|-- Containers/
| |-- UserContainer/
| | |-- UserContainer.js
| | |-- UserContainer.css
| |-- ...
|
|-- Services/
| |-- AuthService.js
| |-- ApiClient.js
| |-- ...
|
|-- Utilities/
| |-- LocalStorage.js
| |-- HttpClient.js
| |-- ...
|
|-- Core/
| |-- User.js
| |-- Product.js
| |-- ...
|
|-- App.js
|-- index.js
|-- ...
This structure reflects the separation of concerns according to Clean Architecture principles, with each layer handling its specific responsibilities. Keep in mind that this is a suggested structure and can be further customized based on the specific requirements of your application.
Those are excellent references to dive deeper into Clean Architecture in React! Here they are:
Clean Architecture With React (Article): This article provides a practical guide on how to implement Clean Architecture in a React application. It walks through the steps to transform a React application into a Clean Architecture structure, offering a hands-on approach to understanding the concept.
frontend-clean-architecture (GitHub Repository): This GitHub repository offers a concrete example of a React application built using Clean Architecture principles, along with TypeScript. It serves as a valuable resource for exploring the implementation of Clean Architecture in a real-world project, showcasing best practices and design patterns.
react-clean-architecture (GitHub Repository): This repository serves as a compelling example of a React application structured using Clean Architecture. It provides insights into how to organize code for maintainability, scalability, and testability in a React project. This resource is valuable for developers seeking practical implementations of Clean Architecture in React.
Vertical Slice Architecture
In Vertical Slice Architecture applied to a React application, the focus shifts from splitting concerns along technical layers to breaking down the system into isolated business functionality. Each business functionality is then further divided into features or slices, akin to how a catalog-bounded context might contain a product aggregate, which, in turn, encompasses various features or slices like CreateProduct and UpdateProduct. Each of these features/slices is entirely independent, minimizing the risk of side effects when making changes.
In this architecture, each user request is treated as a distinct use case, and each request can be divided into "command" requests for write operations and "query" requests for read operations, aligning with the principles of the Command and Query Responsibility Segregation (CQRS) pattern.
Rather than coupling components or modules across layers, Vertical Slice Architecture emphasizes vertical coupling within a slice while striving to minimize coupling between slices. This approach enables the replacement or modification of infrastructure components (e.g., databases, message brokers) specific to a feature or slice without impacting other parts of the system, thanks to the isolation achieved at this level.
In the context of a React application, Vertical Slice Architecture encourages you to group code related to a specific feature or user story together in a single folder. This includes React components, containers, services, and logic related to that feature. The idea is to have everything you need for a particular feature contained within its own slice, allowing you to make changes or updates without affecting unrelated parts of the application.
Here's a sample folder structure for a React application using Vertical Slice Architecture:
/src
|-- features
|
| |-- FeatureA
| | |-- FeatureAEndpoint.js
| | |-- FeatureAHandler.js
| |--components
| | |-- FeatureAComponent.js
| |-- containers
| | |-- FeatureAContainer.js
| |--services
| | |-- FeatureAService.js
|
| |-- FeatureB
| | |-- FeatureBEndpoint.js
| | |-- FeatureBHandler.js
| |--components
| | |-- FeatureBComponent.js
| |-- containers
| | |-- FeatureBContainer.js
| |--services
| | |-- FeatureBService.js
| | |-- …
|
|--shared
| |-- components
| | |-- SharedComponentA.js
| |--containers
| | |-- SharedContainerX.js
|
|--services
| |-- ApiService.js
|-- core
| |-- DomainLogic.js
In this structure:
features is the primary directory where each feature is organized as its own subdirectory.
Each feature (e.g., FeatureA, FeatureB) contains:
FeatureAEndpoint.js and FeatureAHandler.js, which handle requests and logic specific to that feature.
components for React components related to that feature.
containers for higher-level components or containers used to manage the state or logic for the feature.
services for feature-specific services.
shared is a directory for components and containers that are used across multiple features.
services contains any utility services or API services that are used throughout the application.
core holds domain logic or business logic that is not tied to any specific feature.
With this structure, you can work on each feature independently, and any changes made to one feature have minimal impact on other parts of the application. This modular approach also promotes code re-usability, maintainability, and testability. It aligns well with the principles of encapsulation and high cohesion.
Feature-sliced design (FSD)
Feature-sliced design (FSD) is one most popular design approaches which divides an application according to business and responsibility scope. This approach is commonly used in software development and may be used for front-end and mobile applications. FSD.
The idea behind FSD is decompose a application into nested smaller pieces. The first level in “Layer”, each layer may include some smaller manageable pieces that called “Slices”. Slice may break down into “Segments”.
If you want to delve deeper into this, you can visit the Feature-Sliced Design (FSD) website and explore additional FSD examples.
Conclusion:
In React applications, both Clean Architecture and Vertical Slice Architecture offer valuable approaches to structuring code. Clean Architecture's emphasis on layer separation ensures maintainability and tenability by isolating business logic from external concerns, making it well-suited for larger and more complex applications. In contrast, Vertical Slice Architecture promotes high cohesion within features, reducing coupling between them and enabling more efficient feature-specific development and testing. The choice between the two architectures depends on the project's specific requirements, with Clean Architecture favoring long-term maintainability and Vertical Slice Architecture excelling in smaller, focused feature-based development.