As your React.js application grows in size and complexity, it becomes crucial to organize your project in a manageable structure. A well-structured application helps you maintain the codebase, onboard new developers, and easily scale the project.
In this article, we will discuss various approaches to structuring your React.js application and provide best practices to follow.
React.js – Folder Structure Approaches
There are several ways to organize the files and components in a React application. These approaches can be categorized into three main types:
- Group by feature
- Group by file type
- Hybrid approach (combination of feature and file type)
We will discuss these approaches in detail and explore some best practices for organizing your React.js project.
Group by Feature
In this approach, the file structure is based on the application’s features or modules.
For example, consider an online note-taking app with folders for notes, categories, and settings. Each feature folder contains components, styles, tests, and any other related files.
src/
common/
Header.js
Header.css
Utils.js
Utils.test.js
notes/
index.js
notes.css
noteItem.js
notes.test.js
categories/
index.js
categories.css
categoryItem.js
categories.test.js
settings/
index.js
settings.css
settings.test.js
In the “Group by Feature” approach, the application’s file structure is organized based on individual features or modules. In the example provided for an online note-taking app, we have three primary features: notes, categories, and settings.
The src
folder contains a common
folder for shared components and utilities, such as Header.js
, Header.css
, Utils.js
, and Utils.test.js
. Each feature then has its dedicated folder – notes
, categories
, and settings
.
Inside each feature folder, you’ll find an index.js
file as the main entry point for that feature, a CSS file for styling, and any additional components or utility files that are specific to that feature, such as noteItem.js
for the notes
feature.
Furthermore, each feature folder contains a test file, ensuring that the testing code for that feature is colocated with the corresponding implementation.
The advantage of this approach is that it keeps related files together, making it easier to localize changes. The downside is that you may need to identify common components periodically to avoid repetition and promote consistency.
Group by File Type
In this approach, files are organized into different folders based on their type, such as CSS, components, test files, images, and libraries.
src/
components/
Header.js
NoteItem.js
CategoryItem.js
css/
global.css
notes.css
categories.css
settings.css
lib/
utils.js
constants.js
tests/
Header.test.js
NoteItem.test.js
CategoryItem.test.js
In the src
folder, you’ll find separate subfolders for different file types. The components
folder contains all React components like Header.js
, NoteItem.js
, and CategoryItem.js
. The css
folder holds all the styling files, such as global.css
for application-wide styles, and individual feature-specific CSS files like notes.css
, categories.css
, and settings.css
.
The lib
folder is reserved for utility functions, constants, and any other shared code or libraries that the application relies on. In this example, we have utils.js
and constants.js
inside the lib
folder.
Finally, the tests
folder contains all the test files for the various components, such as Header.test.js
, NoteItem.test.js
, and CategoryItem.test.js
. This centralizes all testing-related code in one location, making it easy to maintain and update tests as needed.
This approach offers a standard structure that can be reused across projects, making it easier for new team members to find files. The main disadvantage is that changes in a specific module might require updates across multiple folders.
Hybrid Approach
For larger projects, you may want to consider a hybrid approach that combines the advantages of both Group by Feature and Group by File Type approaches.
This approach organizes common components and styles into separate folders, while also maintaining a clear structure for feature-specific components and related files.
src/
common/
components/
Header/
index.js
Header.css
hooks/
useApi.js
useDebounce.js
features/
notes/
index.js
notes.css
noteItem.js
notes.test.js
categories/
index.js
categories.css
categoryItem.js
categories.test.js
settings/
index.js
settings.css
settings.test.js
In the src
folder, the common
folder contains all shared components, hooks, and other reusable code. The components
subfolder inside common
holds shared components like Header
and its associated styles. The hooks
subfolder contains shared custom hooks, such as useApi.js
and useDebounce.js
, which can be used across different features.
The features
folder contains application’s specific features or modules, such as notes
, categories
, and settings
. Each feature folder contains all the components, styles, tests, and other files related to that particular feature. For example, the notes
folder includes index.js
, notes.css
, noteItem.js
, and notes.test.js
. This organization ensures that all files related to a specific feature are kept together, making it easier to update and maintain the code.
Organizing React “Features” in modern React applications
Modern React applications use features such as Redux, Hooks, Stateful Container Components, Context API, Testing libraries, and Styled-components.
Let’s see how these features can fit into the application structure.
Redux
For Redux, it is recommended to co-locate logic for a given feature in one place. Each feature folder should contain a “slice” file that bundles action types, actions, and reducer logic using the Redux Toolkit’s createSlice API.
This file bundles {actionTypes, actions, reducer}
into a self-contained, isolated module. This approach is known as the “ducks” pattern.
src/
app/
store.js
rootReducer.js
App.js
common/
components/
Header/
index.js
Header.css
features/
notes/
notesSlice.js
index.js
notes.css
noteItem.js
notes.test.js
categories/
categoriesSlice.js
index.js
categories.css
categoryItem.js
categories.test.js
The app
folder contains the store configuration (store.js
), root reducer (rootReducer.js
), and the root component (App.js
). These files are responsible for setting up the Redux store and connecting it to the React application.
The common
folder remains the same as in the previous hybrid structure, holding shared components like the Header
.
The features
folder contains the specific features of the application, such as notes
and categories
. Each feature folder now includes a “slice” file, such as notesSlice.js
and categoriesSlice.js
, which uses the Redux Toolkit’s createSlice
API to bundle action types, actions, and reducer logic into a self-contained module.
This organization ensures that the Redux logic for a specific feature is kept together with its related components, styles, and tests.
Hooks
Hooks can be integrated into the hybrid structure just like any other type of code. Place common hooks at the app level that can be consumed by all React components.
React Hooks used only by one component should remain in the component’s file or a separate hooks.js
file in the component’s folder.
css
src/
common/
components/
Header/
index.js
Header.css
hooks/
useApi.js
useDebounce.js
features/
notes/
index.js
notes.css
noteItem.js
notes.test.js
hooks.js
The common
folder holds shared components and hooks that can be used throughout the application. The hooks
folder within common
contains common custom hooks like useApi.js
and useDebounce.js
. These hooks can be consumed by all React components in the application, promoting code reusability and maintainability.
The features
folder houses the specific features of the application, such as notes
. Each feature folder contains components, styles, tests, and hooks related to that specific feature. If a custom hook is only used by a single component within a feature, it can be placed in the component’s file or in a separate hooks.js
file within the feature folder. In this example, the hooks.js
file in the notes
folder would contain hooks specific to the notes
feature.
Stateful Container Components
A stateful component keeps track of the information itself, instead of just taking it via props and outputting it.
If you structure your code using presentational components and stateful container components, create a separate folder for container components.
This approach helps separate complex stateful logic from other aspects of the component.
src/
components/
Header/
index.js
Header.css
containers/
NotesContainer/
index.js
NotesContainer.css
Here the components
folder contains presentational components that are primarily focused on the UI and are responsible for rendering data. These components receive data and callbacks exclusively via props. In this example, the Header
component is a presentational component with its own index.js
and Header.css
files.
The containers
folder is dedicated to stateful container components that manage state, data fetching, and complex logic. These components are responsible for providing data and callbacks to their child presentational components. In this example, the NotesContainer
is a stateful container component with its own index.js
and NotesContainer.css
files.
Context API
For managing global state, you may use the Context API. Create a contexts
folder at the app level to store your context files.
css
src/
contexts/
ThemeContext.js
UserContext.js
In this structure, the application uses the Context API to manage global state. The contexts
folder is created at the app level to store context files.
The contexts
folder contains all the context files that are responsible for providing and managing global state. In this example, we have ThemeContext.js
and UserContext.js
files. The ThemeContext.js
file may manage the application’s theme (e.g., light or dark mode), while the UserContext.js
file manages user-specific data like authentication status, user profile, or user preferences.
Testing Libraries
Testing is an essential part of modern React applications. Create a __tests__
folder within the feature or component folders to store the test files.
css
src/
features/
notes/
__tests__/
notes.test.js
In this structure, testing plays a crucial role in maintaining the quality and stability of modern React applications. A __tests__
folder is created within each feature or component folder to store the test files associated with that specific feature or component.
The __tests__
folder contains all the test files that correspond to the components, hooks, or any other code within the feature folder. In this example, we have a notes.test.js
file inside the __tests__
folder within the notes
feature folder.
Styled-Components
When using Styled Components instead of CSS, replace component-level CSS files with style.js files. For instance, if you have a titlebar component, the structure would look like this:
plaintext
src/components/button/
index.js
style.js
In this structure, we are using Styled Components, a popular CSS-in-JS library for styling React components. Instead of creating separate CSS files for each component, we create style.js
files that contain the styled components for the respective components.
In the given example, we have a button
component with an index.js
file that contains the component logic and a style.js
file that contains the styled components associated with the button
component.
Additionally, we have an application-level theme.js
file that holds values for common styling properties, such as colors for background and text. This file helps maintain a consistent theme throughout the application, making it easier to apply changes to the design globally.
A globals
component can be created to store common style elements, such as global fonts, resets, or base styles, that other components can use.
React.js Folder Structure – Best Practices
With the improvements to the folder structures we just learnt, you can better organize your React application using modern features and best practices for a more maintainable and scalable project.
In addition to the folder structure, consider the following best practices when structuring your React applications:
- Use import aliasing to shorten long relative paths for common imports. This can be done using both Babel and Webpack configuration.
- Wrap third-party libraries with your API so they can be easily replaced if necessary.
- Use PropTypes with components to ensure type checking for property values.
- Utilize functional components and hooks to manage state and side effects more efficiently.
- Keep component files focused and cohesive. If a component becomes too large or handles multiple responsibilities, consider breaking it into smaller components.
- Implement lazy loading for large components or components that are not immediately required on the initial render, improving overall performance.
@nrwl/react plugin
I wanted to give a shout out to the Open-source @nrwl/react plugin.
This plugin provides an efficient solution to manage React applications and libraries within an Nx workspace. It simplifies your development process by integrating crucial libraries such as Jest, Cypress, and Storybook, while also providing generators for applications, libraries, components, hooks, and more. Additionally, it supports library builds for publishing packages to npm or other registries and offers utilities for seamless workspace refactoring.
Nx is a prominent open-source build system for boosting developer productivity, enhancing Continuous Integration(CI) performance, and ensuring your code maintains quality. It’s a valuable tool for devs looking to rapidly scaffold new standalone projects or entire monorepos. In my opinion, the most powerful feature of Nx is that it evolves with your project, maintaining the flexibility of incremental adoption and scalability. This ensures a smooth development process throughout its growth.
Using Next.js to structure and organize React.js application
Next.js is a popular React.js framework for building complex and performant web applications.
In addition to being a popular choice for building modern web applications, Next.js also is instrumental in enhancing the structure and organization of your React.js applications.
Here’s a quick overview of how Next.js v13 features aid in structuring React.js applications:
1. File-based Routing: Next.js employs a file-based automatic routing system based on your file structure in the pages
directory. This keeps your app structure organized and easy to follow.
2. API Routes: Next.js provides an API routing system that allows you to create serverless functions directly inside the pages/api
directory. This structure encourages separation of concerns, keeping your frontend and backend code cleanly separated and organized.
3. next/script component: Next.js 13 introduces the next/script
component, which provides a declarative way to manage third-party scripts’ loading and execution. By using this component, you can maintain a more organized and structured codebase, as it helps to avoid adding script tags directly to the HTML files or using custom hooks for script management.
4. Built-in CSS and CSS Modules support: Next.js 13 includes built-in support for CSS and CSS Modules, enabling easy import and use of CSS in your components. This contributes to a cleaner and more organized codebase.
5. @next/font: The new font system in Next.js streamlines font management and self-hosting. This feature allows for a more organized and efficient approach to managing your app’s typography, leading to improved performance and reduced layout shift.
6. next/link: The simplified <Link>
component in Next.js 13 makes navigating between pages more straightforward and efficient. Using this component creates a seamless user experience and simplifies internal link handling within your application.
7. Plugins and Middleware: Next.js supports plugins and middleware, enabling you to extend its functionality without changing its core code. This allows for a more modular and organized application structure, as you can create custom logic and features specific to your application’s needs.
8. Development experience: Next.js 13 also introduced Fast Refresh, which provides a better development experience by preserving component state during live editing. While this does not directly impact the app structure, it does allow developers to focus on building features without constantly refreshing the application and losing state, ultimately resulting in a more efficient development process.
Conclusion
A well-structured folder hierarchy is essential when building React.js applications.
Choose an approach that works best for your project size and complexity, such as grouping by feature, grouping by file type, or adopting a hybrid approach. The best practices highlighted in this article, will help you create a solid foundational structure for your React.js application, making it easier to maintain your projects, scale the project, as well as make it easy to onboard new developers, and help them up and running in no time.
This article was technically reviewed by Mahesh Sabnis.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of
DotNetCurry,
DNC Magazine for Developers,
SQLServerCurry and
DevCurry. He has also authored a couple of books
51 Recipes using jQuery with ASP.NET Controls and
The Absolutely Awesome jQuery CookBook.
Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.
Get in touch with him on Twitter @suprotimagarwal or at LinkedIn