How to structure Redux code?

There are many ways to structure Redux code, so which one should we go with?

Before we jump into answering that question, let’s come up with an imaginary application that we’ll use to explore different code structures.

Imagine a note-taking application that has four functions:

  1. Login
  2. Notes can be created
  3. Notes can be listed
  4. Note categories can be listed

What are the parts of our Redux application? The smallest parts are actions, reducers and side effects. Let’s call these parts units.

Units in our application:- login actions, reducer, side effects- add note actions, reducer, side effects- notes actions, reducer, side effects- note categories actions, reducer, side effects

Units combine to form functionalities; these are units closely tied together by the functionality they provide.

Functionalities in our application:- login functionality (login actions, reducer, side effects)- add note functionality (add note actions, reducer, side effects)- notes functionality (notes actions, reducer, side effects)- note categories functionality (note categories actions, reducer, side effects)

Of course, in Redux, the actions and the state is global, so different functionalities can interact. For example, an add note action might cause a change in the notes reducer.

Functionalities combine to form features; these are functionalities closely related to each other.

Features in our application:- login feature (login functionality)- notes feature (add note, notes and note categories functionalities)

To recap, our application is composed of:

  • Units (action, reducer or side effect)
  • Functionalities (grouped units)
  • Features (grouped functionalities)

This is how these layers of the application look together on a diagram. 👇

Now let’s look at the code structuring choices we’re faced with on the functionality and feature levels! (At the unit level, we only have the smallest building blocks, so there’s no organisation to be done)

How to structure code at the functionality level?

1. Group actions, reducers and side effects by file type

/actions
/loginActions
/addNoteActions
/notesActions
/noteCategoriesActions
/reducers
/loginReducer
/addNoteReducer
/notesReducer
/noteCategoriesReducer
/side-effects
/loginSideEffects
/addNoteSideEffects
/notesSideEffects
/noteCategoriesSideEffects

2. Group actions, reducers and side effects by functionality

/login
/loginActions
/loginReducer
/loginSideEffects
/addNote
/addNoteActions
/addNoteReducer
/addNoteSideEffects
/notes
/getNotesActions
/notesReducer
/notesSideEffects
/noteCategories
/noteCategoriesActions
/noteCategoriesReducer
/noteCategoriesSideEffects

3. Group actions, reducers and side effects by functionality and generate actions from reducers (redux-toolkit pattern)

/login
/loginSlice
/loginSideEffects
/addNote
/addNoteSlice
/addNoteSideEffects
/notes
/notesSlice
/notesSideEffects
/noteCategories
/noteCategoriesSlice
/noteCategoriesSideEffects

Now, let’s jump into the analysing the benefits and drawbacks of each approach!

  • Grouping by file type
    benefits:
    - decoupled actions and reducers
    drawbacks:
    - harder to locate code
    - more boilerplate (actions and reducer defined separately)
  • Grouping by functionality
    benefits:
    - decoupled actions and reducers
    - easier to locate code
    drawbacks:
    - more boilerplate (actions and reducer defined separately)
  • Grouping by functionality and generating actions from reducers
    benefits:

    - easier to locate code
    - less boilerplate (actions and reducer defined in the same place)
    drawbacks:
    - coupled actions and reducers

The decision of which approach to go with comes down to this question: what is more important for you?

  • Not grouping related code and decoupling actions and reducers? Group by file type!
  • Grouping related code and decoupling actions and reducers? Group by functionality!
  • Grouping related code and reducing boilerplate (at the cost of coupling actions and reducers)? Group by functionality and generate actions from reducers!

How to structure code at the feature level?

1. Don’t group functionalities by feature

In this case, our file structure will look the same as in the above directory structures where actions, reducers and side effects are not grouped by feature.

2. a. Group functionalities by feature + Group actions, reducers and side effects by file type

/login-feature    /actions
/loginActions
/reducers
/loginReducer
/side-effects
/loginSideEffects
/notes-feature /actions
/addNoteActions
/notesActions
/noteCategoriesActions
/reducers
/addNoteReducer
/notesReducer
/noteCategoriesReducer
/side-effects
/addNoteSideEffects
/notesSideEffects
/noteCategoriesSideEffects

2. b. Group functionalities by feature + Group actions, reducers and side effects by functionality

/login-feature    /login
/loginActions
/loginReducer
/loginSideEffects
/notes-feature /addNote
/addNoteActions
/addNoteReducer
/addNoteSideEffects
/notes
/notesActions
/notesReducer
/notesSideEffects
/noteCategories
/noteCategoriesActions
/noteCategoriesReducer
/noteCategoriesSideEffects

2. c. Group functionalities by feature + Group actions, reducers and side effects by functionality and generate actions from reducers (redux-toolkit pattern)

/login-feature    /login
/loginSlice
/loginSideEffects
/notes-feature /addNote
/addNoteSlice
/addNoteSideEffects
/notes
/notesSlice
/notesSideEffects
/noteCategories
/noteCategoriesSlice
/noteCategoriesSideEffects

Now, let’s jump into the analysing the benefits and drawbacks of each approach!

  • Don’t group functionalities by feature
    benefits:
    - code split into fewer directories
    drawbacks:
    - harder to locate code related to a particular feature
    - may encourage greater coupling of features
  • Group functionalities by feature
    benefits:
    - easier to locate code related to a particular feature
    - may encourage greater decoupling of features
    drawback:
    - code split into more directories

The decision comes down to this question: what is more important for you?

  • Keeping features decoupled and code separated? Group by file type!
  • Having fewer directories (at the cost of not keeping features decoupled and code separated)? Group by functionality!

Conclusion

Ultimately, there is no best way to structure code. Each option has benefits and drawbacks. Therefore, the decision comes down to what is more important for you and your project. I hope this article was insightful, and I wish you good luck with the decision. Happy coding!

Photo by Niels Kehl on Unsplash

Passionate about frontend ✌️

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store