tshaddix / webext-redux

A set of utilities for building Redux applications in Web Extensions.
MIT License
1.22k stars 179 forks source link

How to fix Uncaught TypeError: Cannot read properties of undefined (reading 'state') #286

Closed alex-robert888 closed 1 month ago

alex-robert888 commented 2 years ago

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.

  1. I have a service worker file, background.js, where I use the wrapStore 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")
  1. 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: image image image

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?

dommilosz commented 2 years ago

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...... image For now I would stay at v7 but still I hope it will be addressed and fixed

dommilosz commented 2 years ago

Debugging it I discovered that "this" is undefined only sometimes. image image Edit: all calls with this stack trace are undefined: image and this is the good working stack image

markerikson commented 1 year ago

There's two things happening here:

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.

plusminushalf commented 1 year ago

So the only solution for this is to drop redux to v7?

markerikson commented 1 year ago

@plusminushalf : React-Redux, yeah. Also looks like there's an open PR here in this repo (#289), but it hasn't been merged.

dermeck commented 1 year ago

@plusminushalf if you want to use V8 you can use a workaround to make it work.

One possible solution is described here https://github.com/reduxjs/react-redux/issues/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/ )

jgrisafe commented 1 year ago

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;
};