Organizing your react components

I'm not sure how much this matters in the era where generative AI writes code for you. However, still I embark upon this journey hoping this will help someone write better react code.

Why you should organize your react components

React itselft is unopinonated(probably one of the key reasons why people love react so much) about how component should be organised, and how directories should be placed.

However, organising components in a consistent pattern is necessery, because of the following reasons

  1. Ease of navigating through code

  2. Maintaining Hiearchy helps visualize resulting dom structure

  3. Avoiding Spaghetty Code

  4. Seperating reusable and non reusable components

  5. Ease of composition of complex components

  6. Separation of render-only components from components that contains business logic, or side effects. This is also known as Dumb and Smart Component

  7. Makes Application Preditable.

So, How do I organize my react code?

I follow few levels of seperation to organize my code.

Level 0: All components should have their own directory.

Components should not be exported directly and they should be exported through an index file

.
└── your-component/
    ├── index.ts
    └── Component.tsx

Level 1: Container and Components Pattern

Also known as Dumb and Smart Components, and sometimes known as View/Presentation Components and Smart Components. Let's Elaborate.

  1. Containers(or smart components) are components that handles side effects, often implements business logic and may change state of the applications. These are the components that

    1. implements useEffect for interacting with APIs,

    2. Usually doesn't have a prop.

    3. changes state of the application, by dispatching actions to context api stores or redux state managers.

    4. Does not implement any html markup, just renders dumb components

    5. have no css/scss styles associated

    6. Are the dynamic parts in your application

  2. Components(or dumb components) are the components that does not change applications state and does not handle side effects.

    1. They are static components, just rendering/reacting to the props that are passed to it.

    2. They may implement useState to manage internal state

    3. May implement useEffect without any side effects, like for reacting to window resize, or to determine if clicked outside.

    4. totally dependent on props, and acts like pure functions, ie. always returns same markup, if the props does not change. hence, its easy to memoize these components.

    5. Usually implements html markup with css/scss styles.

side effects: when you interact and change anything outside the scope of your component, its called a side effect. for eg api calls, change in application state etc

Level 2: Atomic Pattern

No matter what people say, there has been no better pattern of organizing your react code. Read more here about it. In this pattern, you divide your code into atoms, molecules, organisms, templates and pages.

  1. Atoms and Molecules are always Dumb Components. They are simple elements like inputs and buttons, paragraphs and images, or a little complex ones, like Hero elements with images, headers with navs and icons, footer with links.

  2. Organisms are the intelligent ones, so they are Smart Components or Containers. These are the components that make your Single Page Applications dynamic.

  3. Templates are often dumb components, and they give the template for the whole page, like the position of static elements like header, footer, sideNav and position of dynamic components like organisms. Usually they are the layout components.

  4. Pages are highest level, they actually provide the real content to components.

Level 3: Directory Structure

.
└── your-react-app/
    ├── App.tsx
    ├── index.tsx
    └── src/
        ├── containers/
        │   └── organisms/
        │       ├── product
        │       ├── cart
        │       ├── home
        │       └── user
        └── components/
            ├── atoms/
            │   ├── buttons
            │   ├── images
            │   └── paragraph
            ├── molecules/
            │   ├── card
            │   ├── hero
            │   └── header
            └── templates/
                ├── home-layout
                ├── cart-layout
                └── product-layout

Rules of orchetrating these components

  1. A Dumb Component can contain other dumb components, usually while creating molecules

  2. A Template Component usually implements the render props pattern, and the children that it renders is usually a smart component or organism

return (<div>
<Header />
  <div>
    {children}
  <div>
<Footer />
</div>);
  1. Smart Components should never implement html markup, instead they should return Dumb Components, which in turn implements the markup

  2. Its better to nest a smart component inside a dumb component instead of prop drilling

  3. Each Component, smart or dumb, should contain its own unit test

Conclusion

I acknowledge that perfecting these patterns takes some maturity and some thought. and it took a while for me to build up the muscle memory for this.

For practical purposes, its better to use a component generator. I have used quite a few component generators, however, over the years they all, one by one started to become inadequeate.

Therefore I created my own component generator that is capable of generating react components that implements both component/container pattern and atomic pattern, with lots of options to customize.

https://www.npmjs.com/package/@jstb/catalyst

You may take a look. Its still evolving, so if you want a feature or discover an issue, feel free to raise an issue in the github.

https://github.com/tirthaguha/jstoolbox

Did you find this article valuable?

Support Tirtha Guha by becoming a sponsor. Any amount is appreciated!