Working without a structure hinders your wokflow. You know you are working with a bad structure if you have to think too hard to find something. Another sign of a bad structure is if your IDE search is not finding files as effectively as it could. A good React Native project structure set up right from the start can help you massively in your projects.
I’d like to share my structure below, as well as some of the thinking I had behind it.
Trying to Organize With a Purpose
I’ve learned to think better about how I am organizing items. It’s good to think about not only how to organize things, but who it will benefit. Also, I have realized that how I categorize is not necessarily the same way a teammate categorizes. What I name files doesn’t always help me find them in search. I’ve learned that to make my daily coding tasks easier to work with I need to think more sensibly.
It’s OK to flatten out some hierarchies
It was hard for me to stop making files and folders everywhere 🤨. Here are some of the things I needed to realize for myself:
- I don’t need a top-level components folder, with separate sub-folders for dumb/smart components. I also don’t need a separate styles folder for those components. This is over-architected.
The redux store folders are spread out and are sometimes confusing to find in the
appfolder. A clearly defined folder that holds this logic and all supporting code, may help.
If I run a search to find a component, I’d like for my component names and the matching style file to be clearly labelled. I also want to know exactly what components are connected to the Redux store and which are not, without a complicated structure.
I want an easy place where I can find my global styling that applies throughout the app.
I typically use React Navigation which could be a little heavy on the configuration side. I’d like to keep this as separate from my app as possible, so that navigation related code is easy to find and manage.
With these main ideas in mind, I decided to go for a React Native project structure that looks something like the below. I have also added some comments next to most to explain the purpose:
- components = Holds dumb components
- containers = Holds smart components, those typically connected to the Redux store
- constants = Holds files that have app constants
- navigators = Holds all my react-navigation navigator configurations
- redux = Holds all Redux related configs, actions, reducers, sagas, selectors, etc…
- theme = Holds styling elements common throughout the app
- utils = Holds functions that serve as utilities for my app
- libs = Holds 3rd party libraries that are not included as an npm dependency
- components = Holds dumb components
- __mocks__ = The Jest mocks
- __tests__ = The Jest tests
- storybook = Storybook stories, if you want to use Storybook
- android = Android project folder
- ios = ios project folder
- node_modules = The auto-generated NPM dependencies
One Note on the components/containers folders
These folders hold my dumb components and those connected to Redux. I have chosen not to add any sub-folders in my React Native project structure, and just let them all live on the first level. This just makes it easier to navigate into through the file system. If I choose good names for the filenames, things should be pretty easy to understand.
I also chose to keep the style files in here, because typically if I open a component I want to open the style file as well. The style and component files will stay together because the style has the same name as the component except with “Style” appended, so this makes things very easy to find. Also, if I search from the IDE, I can easily tell what file is the component and what is the style file.
File naming for better search
Some filenames are easy to find because they are so unique and you just remember them. But tricky ones can be file names that don’t have a pattern you can search for.
An example of this can be a button component called
CallToAction.jsx and one called
ClickForPopover.jsx. These names will not be helpful at all if you weren’t sure of the button’s name and wanted to get a search result list of all the buttons you have in your project.
I like to use a naming convention that includes the type of component followed by the component’s name. With this in mind, a better name for the two buttons above could be
ButtonClickForPopover.jsx. If this naming convention for buttons is enforced, you can find a button in list of all the buttons by just searching for “Button”.
We could also benefit other component types:
PopUpSuccess.jsx — you get the point.
This naming convention is not necessary for all cases, but for some of those components with many variations it works pretty well.
If you want to be extra organized, you can also categorize by the variations you want to distinguish by. For example, buttons that only occurs in the footer could be distinguished from buttons that have a similar function elsewhere:
It depends on your needs though, the size of your app, or your app’s purpose too. Some of this naming convention can become overkill. Just stick with the mindset that whatever you set up is supposed to help you and not hinder you.
I hope my React Native project structure helps you out in your projects, or at least gets you thinking about how you can improve your own structure. Nothing is set in stone, and what works for one team may not work for another.