How to fix Uncaught TypeError: Cannot read properties of undefined (reading 'state')
alex-robert888 opened this issue ยท 7 comments
Hello,
I am trying to use the webext-redux
package and I came across an error which I have a hard time solving.
Basically, I followed the first 2 required steps from the README of the webext-redux repository.
- I have a service worker file,
background.js
, where I use thewrapStore
function to wrap my Redux store. The background script seems to be executing fine, with no errors:
background.js
import store from '../src/store/store.js';
import {wrapStore} from 'webext-redux';
console.log("BEFORE wrap.")
wrapStore(store);
console.log("AFTER wrap")
- I created a proxy store in the React app and passed it to the Provider:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import {Provider} from 'react-redux';
import {Store} from 'webext-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
const proxyStore = new Store();
proxyStore.ready().then(() => {
root.render(
<React.StrictMode>
<Provider store={proxyStore}>
<App />
</Provider>
</React.StrictMode>
);
});
The problem occurs when I try to use a Redux selector in one of my components, to retrieve the value from the store. The store.js
looks like this:
import { configureStore } from '@reduxjs/toolkit';
import reliabilityAnalysisSliceReducer from './reliabilityAnalysisSlice.js';
export default configureStore({
reducer: {
reliabilityAnalysis: reliabilityAnalysisSliceReducer
}
})
reliabilityAnalysisSlice.js
import axios from 'axios';
import { createSlice } from '@reduxjs/toolkit';
// Slice
export const reliabilityAnalysisSlice = createSlice({
name: "reliabilityAnalysis",
initialState: {
shouldShowReliabilityAnalysis: false
},
reducers: {
showReliabilityAnalysis: (state, _) => {
state.shouldShowReliabilityAnalysis = true;
},
hideReliabilityAnalysis: (state, _) => {
state.shouldShowReliabilityAnalysis = false;
}
}
})
// Actions
export const {
showReliabilityAnalysis,
hideReliabilityAnalysis
} = reliabilityAnalysisSlice.actions
// Reducer
export default reliabilityAnalysisSlice.reducer;
And I use the selector like this:
const shouldShowReliabilityAnalysis = useSelector(state => state.shouldShowReliabilityAnalysis);
Which throws the following error:
There are hardly any sources on the internet that could help me, so I would higlhy appreciate if someone could lend me a hand.
Is this this package still supported and funcitonal? Or am I doing something wrong? Any hints on how to debug?
What version of react-redux do you use? I'm getting this error on v8 and it does work on v7. Reading changelogs of react-redux I found that it uses new useSyncExternalStore from react 18. This package hasn't been updated for a while so it may not support this new functionality. In my case it complains about it: at useSyncExternalStore......
For now I would stay at v7 but still I hope it will be addressed and fixed
There's two things happening here:
webext-redux
has itsStore
type written as a class, not as a closure the way the real Redux library does. So,store.getState
inwebext-redux
is actually a class method that relies onthis
- React-Redux v8 passes
store.getState
as an argument touseSyncExternalStore
, which will be called later as justgetState()
. That means that there's nothis
binding applied to thegetState
call.
This works fine with normal Redux, but because webext-redux
uses a class instance that explodes.
Tbh it's almost an accident that this ever worked with React-Redux until now.
So the only solution for this is to drop redux to v7?
@plusminushalf : React-Redux, yeah. Also looks like there's an open PR here in this repo (#289), but it hasn't been merged.
@plusminushalf if you want to use V8 you can use a workaround to make it work.
One possible solution is described here reduxjs/react-redux#1963 . Creating the store like this might fix the problem.
const store = new Store()
Object.assign(store, {
dispatch: store.dispatch.bind(store),
getState: store.getState.bind(store),
subscribe: store.subscribe.bind(store),
})
Another solution would be to use a modified version of webext-redux with the applied fix. This is what I did. (You can find my rough notes in how to do that over here: https://dermeck.github.io/use-modified-npm-package/ )
btw I was having issues with thunk not working in redux toolkit, and this seems to have resolved it.
export const createStoreProxy = (portName: string) => {
const store = new Store({ portName });
const { dispatch: originalDispatch } = store;
// Fix for unresolved bug in webext-redux: https://github.com/tshaddix/webext-redux/issues/286
Object.assign(store, {
dispatch: ((action: AnyAction) => {
if (typeof action === 'function') {
// @ts-ignore
return action(store.dispatch, store.getState);
}
return originalDispatch(action);
}),
getState: store.getState.bind(store),
subscribe: store.subscribe.bind(store)
});
return store;
};