React Native Folder Structure
We’ve built a fair few applications, and we’ve learnt along in the process of doing so.
Lets assume you’re building a full scale React Native application that uses some of the run in the mill tools and plugins that would be necessary for scalable development. I’m talking about:
- Redux (actions and reducers)
- Redux Saga
- Babel
- Bug Snag
- React Navigation
In having all this, we end up falling into a pit of repeated file names, inconsistency in folder and file delegation. “Components within Containers is a common example.” So after scouting across several projects, books and consulting with a few companies on their approach to building a large scale application this is what i’ve learnt.
Use the concept of “processes” or “flows”. Because React Native works in the essence of “Screens” and each screen is ideally part of a user journey we need to accomodate for this. So the folder structure we started using has our main boilerplate app created from initialising react native, we then did it as such:
src
reducers
flows
containers
components
sagas
The reducers followed the ducks principle proposed by the same author who built redux form. This allows for us to store our action constants, our actions as well as our reducer in a singular file, alleviating unnecessary distribution of code across the application.
Flows contain flow structures, “User Login” per se would be one folder, within this folder, we would have multiple screens — I see screens as nothing more than holding compartments that help map the appropriate route with react-nativation.
Each screen would then host one to many containers and each container would respectively have components who’s soul job is to display and act as a means to invoke user induced actions such as swiping and button clicks.
This separation allows for the project to build as large as you’d want without having to fear about folder structure convolution or that your files are being placed all over the application.
With regards to your sagas, create sagas specific to each reducer structure. Wrap all your watchers in a generator function, all yielding to either “takeLatest” or perhaps “takeEvery” call to a particular action. Export this function. Create a mainSagas.js file which collates all your various sagas into one main saga array. This way you can simply to something like
export default function* root() {
yield sagas.map((saga) => fork(saga));
}
Where sagas is an array of all sagas from the “sagas” folder. Last step would be to do
sagaMiddleware.run(mainSaga);
In your file containing your middleware ( We usually place it in a “store” file containing all the config required for creating our reducer.
Also just incase you don’t already know about this, if you are continuously doing something like ‘../../../../’ at the top of each file importing other components, STOP now. Use the Babel Module Resolver — super easy instructions, just place the relevant code in your .babelrc file and you should be able to steam ahead!
All the best, and please leave comments, feed back and suggestions, we’re always learning and finding better ways to improve.
www.Five2One.com.au is a software consultancy based in Sydney, we’ve built products for start ups and large tech firms. We’ve worked with global startups and multi-national companies ranging from the Insurance, Aviation, Law, Car Manufacturing all the way to the Betting industry. Get in touch and lets make software development collaborative, sensible and great!