For answers saying to remove the following line of code
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
Let's first know what does it do:
It tries to check whether Chrome's Redux Devtools extension is available for the Redux store to connect to or not.
Disable extension
- Go to
chrome://extensions
.
- Locate and disable this extension.
- Refresh your app with Chrome Developer tools opened.
- Type
window.__REDUX_DEVTOOLS_EXTENSION__
in the console, it should return undefined
.
Note: This is also the case of Incognito window
Enable the extension
- Go to
chrome://extensions
.
- Locate and enable this extension.
- Refresh your app with Chrome Developer tools opened.
- Type
window.__REDUX_DEVTOOLS_EXTENSION__
in the console, it should return a function definition.
IMO, it should be removed only if you are no more interested to use this extension for debugging purpose for your app. Disabling it does not/should not mean that we completely remove the ability in our code to connect for debugging purpose.
Next, once we know what does this line do, and we are interested to use this extension whenever we want for any future debugging, we should handle both the cases, when extension is available and when it is not available instead of removing the code itself to connect to it.
Basic Store setup
If you have a Basic Store setup as shown below i.e. it does not use middlewares or enhancers
const store = createStore(
reducer, /* preloadedState, */
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
It checks if extension is available, if available call it and if not do nothing which means undefined
. createStore
method seems to properly handle undefined
case and code works fine.
Advanced Store setup
If you have a Advanced Store setup as shown below i.e. it uses middlewares or enhancers using applyMiddleware
or you can say we use compose
const store = createStore(reducer, /* preloadedState, */ compose(
applyMiddleware(...middleware)
));
Code to connect to the extension using compose
is (This is what is the situation in the question)
const store = createStore(reducer, /* preloadedState, */ compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__&& window.__REDUX_DEVTOOLS_EXTENSION__()
));
compose
wants its arguments to be of function
type and finding the devtools extension can return undefined
. And for undefined
cases, it will try to use undefined.apply
method and throws an error. And this is the root cause of the issue.
Solution - Not so complete
As many answered, use window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f
For the undefined cases, it will run (f => f).apply
which executes successfully. But this is more of fooling the compose
method and looks hacky to me.
Solution - Complete
If there a way where I can decide to use compose or not, or a way to enhance the compose method.
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, /* preloadedState, */ composeEnhancers(
applyMiddleware(...middleware)
));
Please note that you need not now check window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
because it has been taken care of in window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
You may verify this code when extension is enabled and disabled (Steps are given above). This should work fine without any issues.
All these code snippets are from the Redux devtools Readme file.
These codes are for debugging on development/local environment only. For production, you may add conditions to opt it out.