Separate your views from your state

Author: Ben Lorantfy
Published: 28 Jun 2019

The Anti-Pattern

Often I see code structures that couple global state to specific pages in an application. This applies to any state management library, but I’ll use redux as an example. Take this file structure:

    /HomePage
      reducer
      saga
      selectors
      index
    /ProfilePage
      reducer
      saga
      selectors
      index
    ...

This is an easy pattern to fall into, but has several problems. For example, say the profile page loads the user data in order to display it, and stores it using its own reducer. That’s fine until we need to access the user data on a different page, e.g. the HomePage. We now have two options:

  1. Import the state from the ProfilePage into the HomePage, tightly coupling the two pages together.

  2. Duplicate the code from the ProfilePage and add it to the HomePage

We either introduce code duplication, or unnecessary coupling, which are both considered harmful in software development. This problem is only amplified the more pages that are added. Imagine several pages all importing from each-other to get certain pieces of state. This can cause a high degree of complicated inter-connected coupling, and/or lots of duplicated hard-to-manage code.

A better way

One alternative to the above architecture is to separate your state management code from your view rendering code. Here’s an example:

    /redux
      /users
        reducer
        selectors
        saga
      /books
        reducer
        selectors
        saga
    /pages
      /HomePage
      /ProfilePage

In the above architecture, the HomePage and ProfilePage import state from the users domain instead of coupling to each-other. We no longer need to write duplicate code, and we don’t have pages coupled to other pages.

Final Thoughts

Separating your state from your views creates a much cleaner and scalable architecture. If at all possible, this anti-pattern of coupling your state to your views should be avoided.