DEV Community

Justin E. Samuels
Justin E. Samuels

Posted on

Fixing the past is hard, how ReduxDevTools and Reselect can help

back to the future mini gif

"Staying stuck in the past is unhealthy"

Who ever said that staying stuck in the past is unhealthy for you was absolutely right, but sometimes there's things we can learn from the past to improve our future actions (pun intended). If you're familiar with the Redux library and its' methodology then you've probably heard of a term called "time-traveling", but could be unsure of what it means and how it can benefit yourself, your application structure and relation to Redux, along with your overall sanity when it comes to debugging state issues in a Redux store. Let's have a closer look at the tools that exist today, before we visit the past (pun intended - again)

Available Arsenal.

  1. Redux-Logger: Is a middleware available for use with the Redux library that allows actions dispatched to be logged to your favorite browser's console. In addition to printing the actions dispatched, the previous and upcoming states are included. This allows you to see the result of the action dispatched in real time, but does not allow you to manually go back in time and replay such an action to further understand its' effects on your store.
  2. Redux-DevTools: Is a middleware available for use with the Redux library similar to Redux-Logger, but instead provides a intuitive GUI to use that's integrated to your favorite browser. Like Redux-Logger, the actions dispatched to the store are recorded and displayed, but a major benefit is the ability to rewind, skip/fast-forward, stop, pause, and play actions that have occurred in your application. In addition, extra configs can be added to really assist in your debugging efforts such as the trace option that will allow you to see where in your app the action was dispatched from.
    I'm sure there's more available logging tools for Redux out there, but these are the two I'm most versed in/seen the most in enterprise applications

Knowing your available tools is most of the battle

flux capacitor getting ready

So now that we know which tools are available, and their usages regarding Redux logging/debugging, lets dive into one of the topics of discussion; Redux DevTools.
To make this an interactive learning experience I've decided to clone a simple boilerplate that came with React, Redux, ReduxDevTools, and Reselect (more on this later) installed. The repo has a good readme which includes how to get everything up and running, so in an effort to keep this tutorial short, I won't be covering this. Once installed and setup we need to add the Redux-DevTools extension to our favorite browser. You can find instructions on how to do that HERE. If you're using the Chrome or Firefox browsers it's a simple plugin install to get it going, if not, follow the instructions in the previous link to get Redux-DevTools setup. Once installed, go back to your cloned application running (if it's not running start it up) and refresh the page. You should see the Redux-DevTools icon glowing......EXCITING!

Is the Flux Capacitor ready yet?

Patience Marty! Before we get into all the cool time traveling aspects of the extension, lets get a feel for some basics of our new extension. Clicking on the extension's icon for the first time will reveal the the actions that was dispatched to the store and the delta (change) that occurred as a result. If there was a change to the state, you would see it here, but since we just got on the page it will say "states are equal" as seen below.

states are equal in Redux-DevTools Extension
Redux-DevTools GUI

You should notice on the top row of the extension an option to switch the view from "diff" to "action". If you were to switch the view you can now see the action itself which includes the type and payload (if applicable) as seen below. action view in Redux-DevTools

Redux-DevTools action view

The last option that we're covering in this tutorial arguably the most important, the "state" view. Clicking on this view will reveal what the store looks like after being reduced from a dispatched action. As seen below, we now have a bird eye view of how our store looks....NEAT! state view in Redux-DevTools

Redux-DevTools state view

Can we go save the dinosaurs yet?

Legend of Zelda - Dont go alone gif

Almost Marty, but I have another feature of our new extension to show you that will assist you from going this journey alone (an old man told me that in 86'). If you're anything like me, looking at JSON or raw objects all day can become dizzying. You may of noticed a sub-option in our new extension called "chart". Clicking on the actions options and the chart sub-option will reveal a nicely drawn graph of the action dispatched and it's relationship to the store's state. This is cool, but where it really shines is drawing the relationship between the action dispatched and the future state.

Go ahead and click on the state option and chart sub-option. You should notice the graph drawn includes the different properties available on the store, and how they interconnect. If you were to hover over the individual nodes on the chart, it will allow you to peek at the current state of that particular property in the store. state view CHART in Redux-DevTools

peek-a-boo, state I see you

If my calculations are correct, when this baby hits 88 miles per hour, you gonna see some serious s**t.

back to the future 88mph

Alright Marty, now that you have a quick overview of our tools, you're ready to go to the past to understand how our future is going to look.
Go to the GitHub input box on our application and begin to type in your or your favorite GitHub user's name and hit enter; You should see a list of repos applicable to that name render on the page. Yay, our application is working as expected, but what actions happened, and in what order, and how did this effect the store's state? Open the Redux-DevTools extension, select the "diff" option and "state" sub-option. Once done, hover over the first action in the list and click the word "jump". You should of noticed the rendered repo list was taken away, your state diff looks different, and the slider near the play button has moved towards the left as well! Marty....we're now in the past! From here you can now click the play icon button and watch the diffs of the states appear and their relationship to what's being rendered onto the screen. Another cool thing is that you DONT HAVE TO DO THEM IN ORDER. For example, you can jump to action 1, then jump to action #4 to see the outcome. That's time traveling in a nutshell, the ability to go forwards and backwards in state to see the effects of an action on your store.

diff replay on Redux-DevTools
Hey DJ, bring it back!

Pro-Tip: Remember our "chart" sub-option from earlier? You can time travel with that option selected as well, which will re-draw the chart in real-time as the mutations as occurring during your playback. You can witness this below. chart replay on Redux-DevTools

Time Traveling Chart

Woohoo, we successfully time-traveled, but what about ReSelect?

Dr.Emmett Brown from Back to the Future

Ah yes, I almost forgot about the ReSelect library and how that can assist us. For brevity I'm going to do a quick overview, and then a more in-depth tutorial in an upcoming post.
First, lets define what the ReSelect library is, and how it works. ReSelect allows you to define functions known as Selectors that uses a concept in Computer Science known as Memoization (Mem-Oh-Ih-Za-shun) which allows us to take advantage of computed values not having to be re-calculated unless there's a significant delta (change) in the expected result. Selectors can be created from other selectors as well, so if a result is dependent or can be derived from another previously created selector, then you can pass it to your new selector to return the upcoming state value. In Redux this is beneficial because we no longer have to view the entire store, when accessing the future state, but instead only pay attention to the specific portion of state that we care about. In addition, this helps with limiting side-effects resulting from state being updated in your store, which would cause a flush of props to your component structure when it probably only cares about a specific part of state. For example, if you had a store such as:
let exampleState = { shop: { taxPercent: 8, items: [ { name: 'apple', value: 1.20 }, { name: 'orange', value: 0.95 }, ] } }
If your component only cared about the taxPercent property on the store, passing the entire state of the store down is useless. Instead, ReSelect would allow you to target and pass only the taxPercent property by doing the following: const taxPercentSelector = state =>
If you were to read this code aloud, it would say "access my the current state of my store object, within the shop property, and return to me only the tax percent property". To put it all together, this would need to go into your connect() HOC's mapStateToProps function Unless this value changes, it will be immediately and readily available in your container/component hierarchy via props for use.
In addition, memoization of computed values are done as described below: ``` const taxSelector = createSelector( subtotalSelector, taxPercentSelector, (subtotal, taxPercent) => subtotal * (taxPercent / 100) )
The above would calculate and return the value of tax on a item based off the value derived from the subtotal and taxPercentage selectors. Notice the createSelector() method that takes in the other selectors - it allows for composability(compose-ability) of values to be computed quickly and only re-computed when there's a delta in the previous result.

Crazy Dr.Brown from Back to the Future

Give it a try: You can play around with the selectors available in our boilerplate via the app\containers\HomePage\selectors.js path. Don't be afraid to break them apart, and reconstruct the. to learn more; it's apart of the learning process!
All this being said, I highly recommend using ReSelect in your application to cut-down on the amount of props being passed to all your components, which can assist in performance by cutting down on useless renders.
Pro-Tip: Renders should only happen on prop or state changes that are applicable to that particular component's functionality/data integrity

Our future is now looking bright!

While this was a quick overview to get you going with improving your debugging of Redux actions and state, I encourage you to continue expanding your knowledge of the tools and libraries mentioned above to improve your codebase. I also encourage you to do a quick google search for more information/tutorials available on this topic, such as this great tutorial by Onsen UI & Monaca Team covering the Redux-DevTools and time-traveling more in-depth. Thank you for coming back to another, but not last tutorial; feel free to leave any comments, suggestions, ideas, feedback for my next tutorial.

Top comments (0)