Common Approaches to Structuring Your React Application
React offers incredible flexibility in terms of letting you build features and structure your app the way you want, but this has also become one of its major pain points. With so many choices, how is a developer or team of developers supposed to decide on what conventions to use?
Designing an application’s structure is much like designing a city’s street layout. Design it well and you’ll have little road rage and congestion. Adding and connecting new developments will be far easier and anyone new to the area will be able to navigate their way around without going in circles or asking for help.
Design it poorly and we start the descent into spaghetti. Which would you rather have?
I’ve been fortunate enough to not only be able to learn about and use React in my own personal projects but also in projects at work and here are the patterns I’ve used along with the pros and cons I found while using them.
The Classic ‘Separate Based on Type’ Approach
Early tutorials and courses I took always seemed to go with this approach. Applications were structured in a way that files were sorted based on their ‘redux type’ — actions, components, and reducers.
I liked this approach and I still find value in it. It helped me start thinking in terms of Redux a lot faster and it doesn’t require much thought when adding more code because you just have to ask whether it’s a reducer, action, or component. It’s rational and easy to grasp.
Where this pattern lost practicality for me was when apps started getting larger and I had to fix a bug or modify something. To change how data flows for one component I had to reach into a minimum of 3 different folders, each one potentially filled 50 other files.
I could have made more nested subfolders within each type folder (action, component, reducer…), and it would have worked fine, but I felt the folder structure would have been nested unnecessarily deep, and until we get easily accessible absolute imports instead of this relative path dot-dot madness, I’ll do my best to keep a flat structure.
The New ‘Separate Based on Feature’ Approach
The basic idea is to separate files into their respective component or feature. If you had a ‘SideBar’ component, then stuff all of its dependencies into a ‘SideBar’ folder — its actions, reducers, components, tests, styles, sagas, and anything else.
Having these self-contained components made it much easier to modify existing files because anything I needed to touch was contained in one folder. It also made it far easier to implement route-based code splitting because every component was self-contained and required no (or minimal) dependencies on files from other folders.
But this approach wasn’t perfect either. It may have solved to problem of having too many actions and reducers to sort through but it introduced the new problem of having too many components. As my projects grew larger I found many components were similar in type, but because I organized them based purely on feature I found that similar components were mixed in with not so similar components.
My generic ‘Sidebar’ and ‘Navbar’ components were getting mixed with page-specific or route-specific or completely different feature-specific components, and to work with a cluster of components for a single page got confusing when mixed with others. It wasn’t too bad, but I knew it could be better.
The ‘Custom Tailored to Your Application’ Approach
So I decided to forget championing any one approach and just started taking the snippets I liked from each one to make an approach tailored to my own needs. I have generic components that I want to reuse over again like ‘Sidebar’, I have containers to hold data, I have ‘routing’ components, and I have ‘pages’: whole-page views that may reuse from the ‘components’ folder or it may use specially customized components. Maybe I’ll make another folder for those types of components.
I’m liking this approach so far, but I’ve also completely changed it over 3 times in the past month. I hope this is ‘the one’.
React’s flexibility is fantastic for experimentation and developing new, customized, and exciting solutions. There is no real right or wrong way to do it, just make sure it makes sense and it solves the problems you have.
Although these are the most common solutions I’ve come across in my readings and experience I know there must be more. Which ones do you use and what do you find great about it? What are the tradeoffs?
I’m a developer who documents new tools and concepts I come across and find interesting enough to share. Please click that heart button and/or leave a comment so I can better cater my content to what you’re looking for.