Structuring your React app is incredibly important for making your project maintainable and easy to navigate. What is the best way to do it?
3 min read
By Kristofer Giltvedt Selbekk
December 3, 2017
Whenever I start out a new app, I tend to ask myself the question, "How should I structure my files?" Truth is, this is a hard question to answer. There is no single right way to make sure the next developer understands where each file should be, and there are tons of alternatives. However, I have a way that has worked for me, and there are several other ones that work just as well. This article is going to outline a few of them.
I tend to split my app into two main topics - components and containers. Containers are basically one-off layout views for a particular route, while components tend to be (mostly) reusable pieces of code. In addition, I separate out state logic (like Redux's dispatchers, actions and reducers) and reusable logical containers. The last piece in the puzzle is utilities. Whenever I bootstrap a new application, I use
mkdir -p to create the following application structure:
src actions components containers dispatchers reducers utils
I tend to create a folder for each component. I add an
index.js file in each of these to simplify importing each component. Inside this folder, I add potential styles, tests, and the component itself. If a component is a bit large and needs to be split into several distinct (but not reusable) components, each of these are also placed in here. Here's an example of how I'd structure a component:
some-component index.js SomeComponent.css SomeComponent.js SomeComponent.spec.js SomeComponentSubPart.js README.md
Depending on the component, and the application itself, I consider adding a
README.md file, as well, explaining the usage and use cases for that particular component. Naming can often only get you so far - sometimes the use case (and limitations) needs some explaining. The same rules go for containers, really.
Actions, dispatchers and reducers always get their own folders in my projects, each with their own
index.js file. For actions and dispatchers, the
index.js file works as an export aggregator, so that I can
import * as actions from '../actions'; instead of remembering which file my particular action (or dispatcher) is from. This practice also pushes me to create unique action (or dispatcher) names for each one - simplifying understanding the code later on. The reducers folder follows the same structure, only with a slightly more complex
index.js file. This time, I export the result of
combineReducers function - so that I can create my store with a simple import.
My way isn't necessarily the only one that'll work for you. Perhaps your projects require a different approach altogether. That's totally fine! Luckily, there are several other approaches that lets you get away with significantly less folders, files and navigation. For simple applications, a "no structure" approach is totally fine. This web app is structured like that, for instance (go check out the source code!). Simply put all your components in the same root folder, and whenever the application reaches a certain size (this one never did), you can consider adding more structure as you go.
There are people that love co-locating tests with the components / logic they test, and there are people that will never see a piece of test code outside a dedicated
test/ folder. Both approaches are fine, and come with their own benefits. To be honest, it's mostly up to taste - so I'm not going to push you either way.