How to structure your files in a large React application — the problem.
As a freelance developper I have had the chance to work on a multitude of React and React Native applications over the last three years. More often than not, it was by joining and collaborating on some existing project. Every single time, as the codebase would grow larger, we would experience the same pain around naming files, tracking dependencies, locating a particular piece of code we needed to work on, and so on. As a result, bugs would creep in, development would slow down, ultimately to the point where someone would suggest starting from scratch.
A traditional file structure
Every codebase I’ve encountered started this way:
At first this looks fine. components
and containers
is where you put your presentational and container components. actions
and reducers
is where you put, well, your actions and reducers (in a standard redux environment).
Soon to be bloated
Naturally, not everything fits within those four folder, so maybe you have a lib
or a utils
folder. Maybe both? Soon, someone decides that thunks
are not enough, and they want to try out sagas
. Of course you write unit tests, with any luck with Jest. You have also heard about the awesome Storybook and have stories for most of your presentational components. Finally, you just have to try the new hotness, GraphQL, and it comes with it’s own queries.
Now the situation looks a little more like that:
At this point, you might be wondering what is wrong with this screenshot. And maybe there is nothing wrong. I mean, where you put your files doesn’t really matter. Things still work. Code still runs. But let’s look at what happens when we start working on the actual files.
Folders are tightly coupled
As an example, let’s build a ticketing website. It will have a Layout, a Homepage, an Artist page, a Venue page and a Search page. It should probably have much more things, like an Event page and a Checkout page and your Account settings and such, but hey, this is just a random contrived example.
The story, all names, characters, and incidents portrayed in this production are fictitious.
Now imagine the time comes, you just got a new Jira ticket assigned to you, and you need to make a change to the way the Artist
fetches data. Here are all the folders you will need to open:
I’ve left out sagas
and tests
because it would not fit on my screen otherwise. Can you count how many times the word Artist
appears? Four times! And four times Home
, four times Layout
, four times Search
, four times Venue
, and so on.
But what about when we are working on a presentational component? We need to update the Header component, which is shared between Artist and Venue page. We want to open the component itself, the story and the unit test associated. It looks something like that:
I don’t know about you, but my head already starts to hurt! Just locating which files I need to open to even get started working on something is daunting. Of course a lot of this can be made easier by your code editor. Just open one file and then click on imports to open the other ones (except that your component doesn’t reference its own stories or tests).
Hard to navigate
You also probably know all your code like the back of your hand. You know exactly where to find which file. You know exactly which component has a unit test or a story and you never break any. You never have any merge conflict either.
But what about that new developper that just joined your project? How do they decide where to put that new component? Is it a container or a presentational component? Are you even sure how to decide that? And what about the you that comes back after a full week of vacation and has completely forgotten how to write a render prop?
And yet, we’ve got no code here
Note also that I was able to fill the file structure with basically no code, and lots of missing pieces. There is only one shared component there for instance. Where are all the Buttons, Icons and our beloved Modal? And because I’m a peaceful person, I won’t even try to bring styling in the mix. Who needs css
anyway? There is also no mocks, no shared prop types, no nothing.
One last example to illustrate how naming can be difficult. Let’s imagine that the Layout
, Artist
and Venue
pages all have some sort of Footer
. But they actually are very different. How do you name the files and the components?
So let’s find a solution!
This structure has three major issues in my opinion:
- It makes code that belongs together hard to discover
- It leaves too much room for inconsistent naming
- It makes reusing and refactoring components difficult
In the next article we will try to solve them with a different approach. Keep reading for How to structure your files in a large React application — the solution.