Keep your Large Redux Application In Check with Redux-Usage-Report

One of the refreshing things about moving to Redux from other types of state management is how easy it becomes to understand what’s going on in your app. You can use Redux Devtools to get a complete picture of the current state, and trace the series of actions that got it there. It’s all in one place, in a single object tree. Everything seems so much more transparent than before.

As your app grows, however, and multiple developers work on features that add more and more data to the store, things can start to get foggy again. Maybe some data is being passed down from the server, but no longer actually used, bloating the store. Or maybe the entities aren’t fully normalized, leading to confusing duplication. Sometimes, it’s simply difficult to discern which components are accessing which parts of the store, or to get a clear sense of how data is flowing through the app.

Codecademy was an early adopter of Redux and, as our app has matured, we’ve dealt with some of these problems. Recently, as I was refactoring part of our store, I started wishing for a tool that would tell me exactly which parts of the Redux store were being used in any given view, and which parts of the store remained completely untouched by the app. Ideally, I also wanted a way to pause code execution when certain parts of the store were accessed, so I could see exactly how our React component tree related to the Redux state tree.

I looked around for such a tool, but my search came up empty. So I decided to build it myself — a store enhancer that outputs a report of your Redux usage, aptly named redux-usage-report.

Let’s look at how you might use it to audit your Redux store.

Practical Guide to using Redux-usage-report

Here’s an example based on a time I wanted to investigate whether the data being passed down from the server in a certain courseProgresses entity was actually used in a particular view of our app.

1. Add the store enhancer

Install the redux-usage-report package and add the store enhancer according to the instructions.

2. Generate the report

Load the app, perform any user interactions you want to register, and then call reduxReport.generate() in the browser console.

3. Inspect the unused part of the report

The unused object returned by the report shows which parts of the store were never accessed. (All screenshots are from the Chrome devtools).

Here, for instance, I see that quite a lot of the courseProgresses data wasn’t needed to render the current view of a course listing page. (If a key is null, that means everything underneath it was not accessed.) It seems that I might want to investigate whether some of the data might be redundant for rendering the current view.

4. Inspect the used part of the report

But which parts of the courseProgresses entities were actually required to render the current view? To answer that question, I can inspect the used key of the report to see which parts of the store were accessed at least once:

It seems clear enough that, for the courses that were actually rendered for this page, the only parts of the courseProgresses entity accessed were the started key, and, if that was true rather than false, the percent_complete key as well.

5. Set a breakpoint

Say I want to see exactly when the started key is accessed. To do this I can type the following in the console:

reduxReport.setBreakpoint('entities.courseProgresses.bySlug.react-101.percent_complete')

After I reload the page, execution will be paused when that value is accessed, and I’ll be able to go down the call stack and see where it’s used.

Here, I see that the percent_complete object is passed to the TrackedCourseCard component as a prop called progress.

How it works

Since state in a Redux store is an object, I had to figure out how to augment a JavaScript object to track which parts of it were accessed, and provide a diff of the used and unused parts on demand.

Luckily, ES2015 offers a convenient new API for adding custom functionality to JavaScript objects: Proxies.

Quick Proxy Interlude

To quote MDN’s proxy page,“The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).” Here’s a brief code snippet demonstrating how a very basic proxy works. This one just logs any usage of an object to the console.

Redux-usage-report uses proxies, along with some extra code to keep track of what has been accessed. If you’d like to take a look at the full implementation of the library, you can check it out here.

That’s about all there is to using redux-usage-report. It might be overkill to use it on a small Redux project or one with few developers, but if you are loading a lot of data into your app up front, or if you have a large store and want a better idea of which parts of it are accessed when, give it a try!

Want to learn more about how we use Redux at Codecademy? Check out my colleague Jon Samp’s article on making the switch to Redux-First-Router.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.