Organizing React Components
- 3 minutes read - 540 wordsYou’re creating a React app, and want to organize your components. Or maybe you’re working in a legacy codebase, with many components in one directory, and you want to better organize them. In this post, I’ll document an approach to this problem that has worked for me.
Besides React, I’ve used this in Vue, Nuxt, and Gatbsy applications. Any JavaScript framework that’s loosely opinionated about directory structures could receive this structure.
The idea: treat components like modules and organize them by route.
So, if you have a dashboard page, the dashboard index and its children are
stored in modules/dashboard/
. Shared components live in modules/common/
.
Imagine I have two routes, login/
and dashboard/
. Here’s my tree:
$ tree src/
├── App.tsx
├── index.tsx
├── modules
│ ├── common
│ │ └── components
│ │ └── Avatar.tsx
│ ├── dashboard
│ │ └── components
│ │ └── Dashboard.tsx
│ ├── login
│ │ └── components
│ │ └── Login.tsx
Yes, this is more complex than one directory. To wrangle that complexity, when I import a component, I’ll use a full path:
import Avatar from 'modules/common/components/Avatar';
Why full paths? Once I’ve imported something once, I can use whole-line
completion, CTRL-X CTRL-L
in Vim, to autocomplete that import into any other
component. It always works, no matter where the component is stored.
The value of this structure appeared to me after continually abandoning two other popular patterns on projects: organization by component, and a flat directory.
Organization By Component
With this structure, I have a component called the Dashboard
and so I have a
directory called Dashboard/
with an index.tsx
and all of its children.
In my experience this adds complexity without meaning. Without the routing, it’s hard to infer when a component is presented to a user. Routing makes it about the experience, rather than how one developer chose to implement it.
Flat Directory
React’s documentation discourages having any initial opinion about your directory structure: “you’ll likely want to rethink it anyway after you’ve written some real code.”
Hey, I get it. YAGNI (you aren’t going to need it). Respectfully, I disagree. Sometimes, you are going to need it.
Starting every project as though there’s no value to anticipating an architecture feels deliberately naive to me. Most well-factored web apps have a lot in common. Presuming routes and reusable components up front feels safe to me.
And there can be a cost to waiting. I’ve worked on legacy JavaScript codebases that badly need to be organized, but there’s no consensus on how, and fixing it is considered low-priority by management.
Perhaps you don’t like traversing this complex directory structure. To that I’d
say: consider using fuzzy find. If I need to open a footer component on a
dashboard, in an app organized this way and with fuzzy find I can type
dashfoo
(“dashboard.*footer”) and most of the time my finder will match
precisely that file. That boring obviousness is the goal.
Conclusion
I learned about this technique a few years ago, in a blog post I can’t find. Please reach out to me if you’re the author and I’ll add an attribution.
In the meantime, it’s important to write my interpretation it in case that post no longer exists. I hope it helps.