reduxjs / react-redux

Official React bindings for Redux
https://react-redux.js.org
MIT License
23.38k stars 3.36k forks source link

Redux Toolkit Query 2.0 Beta Uncaught Error: could not find react-redux context value #2020

Closed jonaldinger closed 1 year ago

jonaldinger commented 1 year ago

What version of React, ReactDOM/React Native, Redux, and React Redux are you using?

What is the current behavior?

When upgrading from react-redux 8.0.5 to 8.0.7, along side of Redux Toolkit 2.0.0-beta.0 + Redux 5.0.0-beta.0, my application code throws an error when using an RTK Query hook:

Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
    at useReduxContext (useReduxContext.js:24:11)
    at useStore2 (useStore.js:17:9)
    at useDispatch2 (useDispatch.js:14:19)
    at useQuerySubscription (buildHooks.ts:689:24)
    at useQuery (buildHooks.ts:964:42)
    at RequireAuthentication (RequireAuthentication.tsx:34:7)

The application code is wrapped in a Provider and has been functioning normally for months with the Redux Toolkit alphas, and is also functioning normally with the just-released Redux Toolkit beta. It is only when I upgrade to react-redux 8.0.7 that the error is thrown. When I downgrade to react-redux 8.0.5, without modifying any other dependencies, the error is not thrown.

Interestingly, useSelector(), which I would assume is accessing the same exact context from the provider, works fine. But useGet*Query() from RTK Query throws. Final note, I am using Yarn PnP and Yarn Workspaces.

What is the expected behavior?

No error should be thrown, as the component is wrapped in a provider.

Which browser and OS are affected by this issue?

Chrome 113 on macOS Ventura

Did this work in previous versions of React Redux?

EskiMojo14 commented 1 year ago

My assumption is that you're using a custom context, and providing the hooks to the react API module.

One of the breaking changes made in RTK's alphas/betas (I'm unsure which one) is that the signature of reactHooksModule changed: https://github.com/reduxjs/redux-toolkit/pull/3400

reactHooksModule({
    hooks: {
      useDispatch: createDispatchHook(MyContext),
      useSelector: createSelectorHook(MyContext),
      useStore: createStoreHook(MyContext),
    },
  })

This is likely the main thing that's causing your issue.

jonaldinger commented 1 year ago

Thanks for the reply @EskiMojo14. I'm not using custom context, just the standard createApi() which is added to the reducer object in a standard configureStore(). The weird part here is that my application code works totally fine with all versions of the RTK alphas/betas. It only breaks when upgrading from react-redux 8.0.5 to 8.0.7 (along side of either RTK 2.0.0-alpha.5 or 2.0.0-beta.0 - I haven't tested with other versions). And there don't seem to be many actual material changes in those react-redux updates between 8.0.5 and 8.0.7 - mostly documentation. One exception is a rather large update to the lockfile, which could possibly be impacting dependencies?

EskiMojo14 commented 1 year ago

it's possible you have multiple versions of react-redux - try running npm ls react-redux

jonaldinger commented 1 year ago

I'm using Yarn PnP with Workspaces, but the following is equivalent. I also verified I have single versions of React, ReactDOM, Redux, and Redux Toolkit.

Screenshot 2023-06-02 at 6 03 22 PM
EskiMojo14 commented 1 year ago

interesting, that's really odd - would you be able to make a recreation in codesandbox?

markerikson commented 1 year ago

@jonaldinger : the lockfile updates were just me updating the website folder from Docusaurus 2.0-beta to 2.4, no runtime or devdep changes.

I would be very curious to see a repro of this.

Or, even better, could you make a Replay recording and share that here?

https://replay.io/record-bugs

jonaldinger commented 1 year ago

Thanks so much for the responsiveness @EskiMojo14 and @markerikson. I'm about to sign off for the weekend, but will try to create something useful to help debug next week. FYI this isn't actively blocking, everything works 100% if I stay on react-redux 8.0.5 even when I update everything else to latest including alpha and beta versions. I opened the issue just as a proactive measure to sniff out a potential issue with the beta.

phryneas commented 1 year ago

You actually have four different instances of the same version of react-redux installed here - see that hash in the square bracket after the version number. Those four versions will not be able to interact with each other - you'll have to play around with that to get them to the same instance.

jonaldinger commented 1 year ago

@phryneas great spotting. That seems very likely to be the issue, as the working state with 8.0.5 has a common hash across all workspaces:

hash

I'm not sure what's driving that change with the upgrade, but let's assume it's on my end. I'll do some tinkering. Thank you!

shermify commented 1 year ago

I'm actually running into this same bug with redux-toolkit 1.9.5 and I don't think there is an easy workaround.

I could be wrong, but my guess is that adding redux-toolkit 2.0-beta to react-redux peer dependencies has broken yarn pnp due to the circular peer dependency between the two packages. This forces yarn to create virtual instances of both packages in every workspace because it cannot guarantee the dependency tree will be the same across workspaces. As you can see below, the hashes in those screenshots indicate dependency trees, not duplicate packages. If react-redux requires a singleton package, this is going to be a problem for anyone using yarn workspaces.

Screenshot from 2023-06-19 14-44-44

markerikson commented 1 year ago

That... sounds horrifying.

I have no idea what to do about that.

I guess I could remove RTK from the React-Redux peer deps?

shermify commented 1 year ago

Perhaps someone more knowledgeable about yarn can chime in to make sure I'm not talking out of my backside, but I made a simple repro here

https://github.com/shermify/react-redux-repro

It's a common pattern for workspaces to share a package that exports RTK slices and apis. Works with react-redux 8.0.5 but not 8.1.0 due to the above issue.

phryneas commented 1 year ago

We can probably get rid of that singleton going forward, but that will only fix future versions.

jonaldinger commented 1 year ago

@shermify thank you for the info and repro. I did some more local testing over the past few days and am seeing the exact same thing as you (single installed dependencies, but multiple virtual instances of both RTK and react-redux). I tried tweaking lots of things, but always got the same outcome. I think your theory sounds correct:

I also have the same feature use case - a monorepo (Yarn Workspaces) that has multiple apps that connect to common APIs. The core workspace defines the shared slices, which are then imported and consumed by multiple other app workspaces. This setup has been working great up until now (and I've been using the RTK alpha for many months).

It feels reasonable that the peer dependency would be declared in either RTK or react-redux, but not both. And I'm not an expert here, but it actually seems to make more sense to remove the peer dependency from RTK instead, since that's the "larger/core/foundational" library (it's my understanding that you can technically use RTK without react-redux, but you can't use react-redux without react and redux or RTK). For example:

@markerikson @phryneas again appreciate the responsiveness and discussion!

EskiMojo14 commented 1 year ago

the issue is that there are entry points in RTK (@reduxjs/toolkit/query/react already in 1.x, @reduxjs/toolkit/react added in 2.0) that directly use react-redux. on the other hand, there is no code in react-redux that uses RTK. it depends on redux core types, but nothing from RTK itself.

as such i'd argue it'd make more sense for RTK to have the peer dep and react-redux not to

markerikson commented 1 year ago

Yeah, I can try removing it from React-Redux

jonaldinger commented 1 year ago

Ah ok, thanks for the context. At that point, if RTK 2.0 is now directly importing code from react-redux internally, would it make more sense for react-redux to become an actual dependency of RTK rather than an optional peerDependency? (feel free to say absolutely not - I don't know the larger considerations/implications there 😄).

EskiMojo14 commented 1 year ago

it's an optional peer dependency because it's entirely possible to use RTK without react-redux - it's just the react specific entry points that would need it, basically

shermify commented 1 year ago

FYI, if you list react-redux and redux-toolkit as peer dependencies in your shared library and remove them as direct deps, it should fix the issue because then it ensures the shared library is using the correct react-redux instance provided by each app. This is probably the right way to do it so long as react-redux requires a singleton package. It's definitely not obvious at first and will trip a lot of people up though. You have to make sure the last package in your dependency chain provides react-redux and redux-toolkit, and all the others pass them on as peer dependencies.

I'm not sure if removing redux-toolkit from react-redux peer dependencies alone will solve the issue because there were other changes to both package's dependencies that could cause branching. I think the reality is this pattern will be fragile as long as react-redux requires a singleton.

phryneas commented 1 year ago

@shermify going forward, we should be able to solve that "singleton context item" problem with #2039.

markerikson commented 1 year ago

I'll see if I can get out 8.1.1 tonight with the context fix and the peerDep removal

markerikson commented 1 year ago

okay, 8.1.1 is out:

https://github.com/reduxjs/react-redux/releases/tag/v8.1.1

Please let us know if that fixes things!

jonaldinger commented 1 year ago

@markerikson, the dependency hashes with v8.1.1, they're beautiful 🥲 Fixed for both RTK and react-redux. Oh and also all of the behavior is seeming back to normal. I clicked around a bunch in different apps and saw no occurrences of missing context. Thanks all! I even learned some new things through this.

react-redux-hashes

shermify commented 1 year ago

Works for me. Thanks for being on top of this so quickly!

jonaldinger commented 1 year ago

Everything remains rock solid, so closing. Thanks again!