Necessity is the mother of invention — but Rails is the mother of convention. And sometimes, what you really need is some structure.
Here at 20spokes, we have branched into mobile in a big way, using React Native with Rails APIs. As a consultancy, we have the unique perspective of building projects from scratch often, and we kept coming back to folder structure. Namely, how on earth does anyone find anything in a React Native (or React.js) app as it grows?
Most of the React tutorials we saw out there had three main folders for their files: elements, modules, and components. (Redux projects will sometimes expand that to include an actions folder.) But try getting someone to actually define what an element is, versus a module, versus a component, and the argument quickly becomes circular. Elements are reusable, they say. Well, so are modules. Modules are bigger, though. Sort of.
So we decided to write our own rulebook. Trash it if you like, but it’s worked pretty well for us so far, and going back to maintain projects we built before we established this style? The difference is mind-boggling.
|_ __tests__ |_ ...mirrors the src folder |_ android |_ assets |_ ios |_ src |_ actions |_ contexts |_ Profile |_ modules |_ AvatarUploader.js |_ views |_ EditProfileView.js |_ PublicProfileView.js ProfileStyles.js |_ elements |_ Buttons |_ ButtonPrimary.js |_ ButtonSecondary.js |_ helpers |_ layouts |_ navigators |_ utils App.js index.js
Along with this folder structure, we’ve employed
babel-plugin-module-resolver to help with the dreaded strings of
../../../../ before import statements. That way, every time we need a common element in a view within the contexts folder, the import path can be as simple as
elements/Buttons/ButtonPrimary.js. Learn more about that plugin here — it’s been key to our success with this structure.
Putting it into contexts
If you’re building any kind of mildly robust mobile application that makes requests to an API, you probably have several "flows" through the app. Settings. Login. Feed. Profile. Onboarding. Any "section" of the app that you’ve probably already chunked out as a feature set is probably also a context. We decided to create a folder for each of these contexts, with all the views in that context along with all of the modules/elements that are particular to that context. 
For example, a public profile view, an editable profile view, and an avatar uploading module would all be in a Profile context folder. If an element is reusable outside of that component, stick it in the elements folder instead. The contexts folder was the real heavy-hitter in our redesign. You’re welcome.
Let me lay it out for you
Most of the apps we create have custom navigation bars/drawers or
SafeArea wrappers that need to go on every page. We usually call this a
TopNav.js, whatever the use case is. Sometimes different kinds of views have different view wraps. The layouts folder is for these — just like in Rails.
Check the GPS
The navigators folder is a handy place for all your navigation-related files.
If you’re familiar with navigation libraries for react like React Navigation, you know that each app "flow" needs a navigator file or something like it. We used to keep these in the junk pile, AKA the top level of the folder structure along with
index.js. But for complex apps with lots of form flows, or different user journeys, having a navigators folder — with subfolders like Admin or Onboarding or other, more specific navigational needs — makes it a lot easier to grok the app’s navigational complexities.
Going off the Rails
As a software consultancy, we have a particular interest in making sure that our code is easy to read and maintain by another team sometime down the line. But let’s be honest — we’ve all read a codebase that we wish had been written with future developers in mind.
Going back to old projects, ones built before we adopted this new folder structure, isn’t a total nightmare (we have always been pretty good at this readability stuff, after all). But it truly is amazing how much of a difference the new structure has made. No longer do I have to wonder which Events folder is going to have
EventCard.js in it —
src/modules/EventCard.js? There’s only one Events folder,
src/contexts/Events. Something reusable like a card will maybe be another folder deep, in a
modules folder particular to events. But that’s it. No more digging!
Even if you decide not to implement our folder structure for your next React or React Native project, what I hope you’ll take away from this success story is that it’s invaluable to consider lessons you’ve learned from other frameworks. What makes Rails infinitely easy to jump into and know where to look for things is totally doable in React. So get after it!