React 101: Directory Structure

koralarts

Karl Castillo

Posted on September 25, 2022

React 101: Directory Structure

Context

Creating a React-based application can be daunting because React doesn't provide certain directory structure. Many people have their own structures. Like them, I have my own opinion as well.

Component Hierarchy

I view components based on their usage. In general, I see 3 types of components -- common, feature and page.

Common components are components that can be used in a generic fashion like Button, Modal, Accordion, etc. These components are meant as building blocks of your application.

Feature components are components that is used by a specific feature. You can view features as an offering you provide for your users. A feature component can be Authentication, User, etc.

Lastly, page components are components that allows users to use your features and common components. These could be Settings, Profile, etc.

Dependencies

The three types of components have a set of rules on how they could interact with each other.

Common Feature Page
Common
Feature ✅ if same feature
Page ✅ if same page

✅ - can use component

The reasoning for the rules is because we want a separation of concerns between the different tier of specificity. What I noticed after an application gets bigger, many components become intertwined into other places.

Advantages of structuring your following the three tiers are:

  • Semantic naming of directories makes it easier to visualize the codebase and for new engineers to understand it.
  • Absolute paths using aliases will be more understandable.
import { Button } from "@common/Button";
import { Dropdown } from "@common/Dropdown";
import { UserAvatar } from "@features/User/components/UserAvatar";
Enter fullscreen mode Exit fullscreen mode
  • Building new pages will be simpler because you won't need to worry about where your core functionality will live.
  • This will urge designers and engineers to be more consistent or use existing components since the structure is meant for reusability

Example:

app/
|-- common/
   |-- Layout/
       |-- __tests__/
       |-- stories/
       |-- index.ts
       |-- Layout.tsx
       |-- Layout.scss
   |-- Button/
       |-- __tests__/
       |-- stories/
       |-- index.ts
       |-- Button.tsx
       |-- Button.scss 
   |-- Modal/
       |-- __tests__/
       |-- stories/ 
       |-- components/
           |-- ModalHeader/
              |-- index.ts
              |-- ModalHeader.tsx
              |-- ModalHeader.scss
           |-- ModalContent/
              |-- index.ts
              |-- ModalContent.tsx
              |-- ModalContent.scss
           |-- ModalFooter/
              |-- index.ts
              |-- ModalFooter.tsx
              |-- ModalFooter.scss
       |-- index.ts
       |-- Modal.tsx
       |-- Modal.scss 
|-- features/
     |-- User/
         |-- __tests__/
         |-- stories/
         |-- components/
             |-- UserAvatar/
                 |-- __tests__/
                 |-- stories/
                 |-- index.ts
                 |-- UserAvatar.ts
                 |-- UserAvatar.scss
         |-- hooks/
             |-- useUser.ts
             |-- useUserMutations.ts
         |-- constants.ts
         |-- helpers.ts
|-- pages/
    |-- Settings/
        |-- __tests__/
        |-- components/
            |-- UserTab/
                |-- __tests__/
                |-- stories/
                |-- index.ts
                |-- UserTab.tsx
                |-- UserTab.scss
        |-- index.ts
        |-- Settings.tsx
        |-- Settings.scss
Enter fullscreen mode Exit fullscreen mode

Other files/directories that can exist within the structure are:

  • __tests__
  • contexts
  • constants
  • helpers
  • hooks
  • stories

Why index.ts

To make it even simpler for engineers to find what they need, we use index.ts as an entry-point to the component while having a named file for the actual implementation.

// without index.ts
import { Button } from "@common/Button/Button";

// with index.ts
import { Button } from "@common/Button";
Enter fullscreen mode Exit fullscreen mode

Weakness

Like any other directory structure, it's not perfect. This directory structure is opinionated in a sense that your team needs to decide on what you would consider as a feature. For example, is User different from UserProfile? Can UserProfile live under User.

Another weakness that people might not like is how nested the directories can be.

Conclusion

This directory structure is meant to have a semantic way to structure your application. It's not meant to be a be-all and end-all solution. It's simply a solution that had made sense and worked for me.

If you liked certain aspects of this directory, and would like to adopt them; let me know in the comments on how you plan on adopting it. If you didn't like it or have suggestions on how to improve it, let me know in the comments.

References

https://reactjs.org/docs/faq-structure.html

💖 💪 🙅 🚩
koralarts
Karl Castillo

Posted on September 25, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

React 101: Directory Structure
react React 101: Directory Structure

September 25, 2022