React.js Application Structure - Best Practices

Posted by: Suprotim Agarwal , on 7/23/2023, in Category Reactjs
Views: 34425
Abstract: This article discusses best practices for structuring React.js applications, focusing on three main approaches: Group by Feature, Group by File Type, and a Hybrid Approach. The tutorial also covers how to integrate modern React features, such as Redux, Hooks, Stateful Container Components, Context API, Testing libraries, and Styled-components, into the application structure.

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.

React.js app structure

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.

Absolutely Awesome Book on C# and .NET

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!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
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



Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!