Troubleshooting React with Redux & Redux DevTools

It's not really uncommon to come across TypeError: Cannot read property 'apply' of undefined when you are using React & Redux, but it's specifically tough to understand why it comes up when it works in your computer, but doesn't in your co-workers. This is the exact issue I faced today, found the root of the issue and solved it too.

Problem

This is what happened. I had a happy working React App in my machine. I thought of demonstrating what I have done so far with my colleagues, I made my local machine as a React JS Server and tried to serve the URL to everyone in my team. But alas! It didn't work out for me. I get the following error, in multiple flavours, as my colleagues were using different types of machines - Windows, Linux and macOS (me).

Error Message

But one thing was common in all the messages. The error was Cannot read property 'apply' of undefined, and this seemed like there something that was expecting a function (as apply will be mostly a property for functions and something might have tried applying this function on some object) and it found an undefined instead.

I wasn't really sure what was happening. For the record, I fought with my team to get myself a macOS and now if this is causing so much trouble, they might as well tell me to develop the whole thing from scratch on a Windows OS machine, which might come to me as a terrible news. Having this said, I was determined to fix the problem, as it came when I did a client presentation! I know by now my reputation is at stake.

Debugging Sh!t...

When I went through the error stack, which many developers don't normally do, including me, and instead try to look up the issue on the so called "Dev Bible", Stack Overflow and I fell in the same trap too! I was searching for issues like, "it works with mac but not windows" and other crazy stuff, but didn't think of looking through the stack trace for what it says! I know! 🤦🏻‍♂️

After gaining some courage, I thought of checking out the stack trace anyway, in order to understand what the hell is going on in the code and how React JS is perceiving it. After going through for about ten to twenty times (yes, I swear, it didn't strike me immediately), I found something interesting or maybe annoying. It's something to do with Redux!

The error occured in the process of creating the Redux Store, where I have had the following definition.

export default createStore(  
  rootReducer,
  compose(
    applyMiddleware(thunk),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
  )
);

I really didn't expect that naive code was the root of all problems. So let me explain what's exactly happening here. The compose() function does some great work of combining all the reducers available, the root reducer, middleware function and enhancements, if any. All the parameters of compose function are supposed to be functions.

Now let's say if your browser doesn't have the Redux DevTools Extension, you have gotten into a severe problem. Technically, undefined && undefined() will be apt when the return value isn't being used anywhere. But here, that's not the case. We are passing the return value of the check to the enhancer, which expects a function.

Solution

The above code of checking for the existence of Redux DevTools and returning the factory is suggested by Redux DevTools team. There are also an issue concerning that the particular code not working. After browsing through the issue's discussion and trying to understand what's happening behind the scenes, I tried to do a lot of trial and error and came up with the following code that works!

export default createStore(  
  rootReducer,
  compose(
    applyMiddleware(thunk),
    typeof window.__REDUX_DEVTOOLS_EXTENSION__ === "undefined"
      ? a => a
      : window.__REDUX_DEVTOOLS_EXTENSION__ &&
          window.__REDUX_DEVTOOLS_EXTENSION__()
  )
);

I check for the existence of the Redux DevTools in the window object and if don't find it, instead of doing a short-circuit, I tried using a ternary operator that returns a function that returns the first parameter when invoked. Woah, and it worked. This can potentially be a solution or Redux DevTools can do a type-check before calling the apply() method.

And, here we go...

Working Solution

Let me know your comments about this approach and if this works for you, please do share with others too to save at least an hour's time in finding out how to work with this crazy issue. 😇



comments powered by Disqus