Here is how you write scalable and maintainable React components for projects of any size.

·

3 min read

We all know React is a library and not a framework, and that, unfortunately, is it's biggest drawback.

Compared to the other 2 popular frontend frameworks out there; Angular and Vue, React really is the odd child.

I wholeheartedly believe that we all should be using frameworks rather than libraries to create SPA (single-page applications); as it gives structure to the code base. The reason why React is the most popular of the 3 is that it is a library, and developers can "whip" something up quickly without following the strict guidelines of a framework. This is one of the main reasons why it propelled React to the top of the popularity scale.

Open positions for React, Angular and Vue developers for October 2018. Ref

But just because something is popular, doesn't mean it is the best. Given that it is an unopinionated library, developers have free rain on how they structure their code base; or not structure it at all. This isn't a good thing majority of the time, especially for larger projects. I have seen a lot of crazy React code in my time, and let me tell you, it is CRAZY. I have worked with code bases that are one index.js file long. And other instances where all the components for one page is in one file.

We all have heard the phrase "React is good for small to medium size projects, but for larger projects, use Angular". Although there are truths to this, I believe React can be good for larger projects if it is structured properly.

Throughout my career, I have undoubtedly found the best way to write React; I call this the "Smart container, dumb component" method of writing React components. This method allows the project to scale and is easily maintainable.

Here is how this works; if we want to render the user list to the screen, we would create a dumb component (dumb components re-render on prop or state change) called UserList.ts which is only responsible for displaying the user list plus the loading and error states.

const UserList = ({isLoading, hasError, userList}:props) => {
  return jsx
}

Then, we would create another file called UserListContainer.ts which will be our container component where all business logic resides. Such as making API requests, data manipulation and passing state to the dumb component.

const UserListContainer = () => {
// make API request
// manipulate the data
  return <UserList 
          userList={userList}
          isLoading={isLoading}  
          hasError={hasError} />
}

Note: one file should only contain one component.

We will do this for each component in the application, the folder structure will look like the following:

src
  userList
     UserListContainer.ts
     UserList.ts
     UserList.stories.ts
     UserList.test.ts
     index.ts // this is responsible for exporting the component

Now, to use UserList component, we will import the UserListContainer to where we need it. When the UserListContainer mounts on load, it will make a query call for the user list data, manipulate the data, and pass it to the UserList component.

With this separation of concern, we can all write scalable and maintainable React code; code that is not only for ourselves but for every other developer who will be working on the project.