Organizing Your React + Redux Application’s Codebase for Future Maintainability and Extensibility

The State-View Pattern

Recently, I’ve been working on a pretty complex React + Redux application, for which I experimented with a new pattern of organizing my application’s codebase. This is an evolution of the ‘feature-based grouping’ approach to organizing your code. Pretty much the only issue (albeit a major one), of the feature-based grouping approach, is unpredictability with regards to state, when the state does not map one-to-one with views.

In order to eliminate this unpredictability, we split the codebase into two seperate main directories, and files are grouped based on different factors in each directory. As you may have guessed, these two directories are the state and the view directories.

All state management related code, including all actions, reducers, middleware and stores are put into the state directory. All other code is put into the view directory. So how are these directories further organized?

Let’s first look at how the overall application structure looks when the real-world Redux example is rewritten to use the State-View pattern:

There are the two main directories state and view. Let’s explore the view directory first.

  • Root – The root container component which performs routing and renders other components. All state management related code is removed from here, and only view specific code is retained. We have also renamed the container component and suffixed the file with Container to indicate it as a container component.
  • App – The main application component. You may notice we have renamed the Explore component to ExploreComponent. This is to indicate this as a presentational component.
  • DevTools – Is responsible for the DevTools which log the state as it transitions with each action.
  • RepoPage and UserPage – These directories correspond to the RepoPage feature which lists the starred watchers of a repo, and a UserPage feature which lists the repos a user has. As you can see, these directories only contain the view components and all actions and reducers have been removed.
  • _shared – All the view components which are shared between multiple features, are grouped together here.

As you can see the view directory is organized extremely similarly to how the application is organized in the feature-based grouping pattern. The reason for this is pretty simple. There was no real issue with the way the view components were organized in the feature-based grouping pattern, so we just left it as is.

Now let’s look at the state directory. This is where the majority of the changes from the feature-based grouping pattern occur. First off, you will notice that the names of the subdirectories inside the view directory do not at all correspond with those of the subdirectories inside the state directory. This is completely intentional, and is done to enforce the idea that the state does not have a one-to-one mapping with the view.

Instead of organizing the state directories contents by application feature, we organize them by the properties of the store that they are responsible for. In the real-world redux example, the state of the application looks something like this:

const state = { 
errorMessage: null,
entities: {},
pagination: {}
};

If we go back to the state directory, the subdirectories correspond to the properties of the state. Each subdirectory contains the actions and reducers required for manipulating that particular portion of the state. Any commonly shared items, are placed in the _shared directory. These actions and reducers are then rolled up and combined, by using the actions.js and reducers.js files in the state directory, and they are then exported by the index.js. So now, if we need to use a specific action in any of our view components, we can require it like this:

import { actions } from '../../state'; 
const { loadRepo, loadStargazers } = actions;

If you want to have a look at the code for the state-view pattern for the real-world redux example application, the source for that is available on Github.

read original article here