Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reactive variables stop working with Fast Refresh #6661

Open
marioaks opened this issue Jul 21, 2020 · 4 comments
Open

Reactive variables stop working with Fast Refresh #6661

marioaks opened this issue Jul 21, 2020 · 4 comments

Comments

@marioaks
Copy link

marioaks commented Jul 21, 2020

Hi,

I just started using Apollo Client v3 and reactive variables in my react-native-web app. I've also been using a webpack plugin that enables "Fast Refresh" (https://github.com/pmmmwh/react-refresh-webpack-plugin). I've run into a problem where, whenever I update a file that triggers a fast refresh, my reactive variables essentially stop working.

I'm using the following code:

export const userVar = makeVar(null)

export const typePolicies = {
  Query: {
    fields: {
      user() { 
      	return userVar() 
      }
    }
  }
}
const UserProfile = () => {
    const { data: { user } } = useQuery(GET_USER)

    //I also tried this method:
    //const user = userVar() 

   return (...)
}

Intended outcome:
Normally, if i call userVar(newUser), the UserProfile page will rerun the query and return the new user. This is what should happen even after a Fast Refresh is triggered

Actual outcome:

Once fast refresh is triggered, calling userVar(newUser) doesn't rerun the query and the UserProfile component doesn't rerender.

How to reproduce the issue:

Add the following code to your webpack.config.js to enable fast refresh:

const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");

if (env.mode === "development") {
    config.plugins.push(
        new ReactRefreshWebpackPlugin()
    ); 
}

Versions

@apollo/client: 3.0.0

@benjamn
Copy link
Member

benjamn commented Jul 21, 2020

Does the fast refresh plugin have any sort of API that modules can hook into to clean up / recreate resources before/after the module is refreshed? If I recall correctly, Webpack had a module.hot API, but I haven't seen it used or mentioned explicitly in a while, and I wonder if it still makes sense in the post-CommonJS (require, exports, module) world.

Worth mentioning: hot module replacement systems tend to disregard resource management by default, except in narrow cases (like with React components) where the system has been designed around refreshing a particular type of module with a particular kind of export (i.e. just a single React component). Getting it to work well in general requires some manual effort, which almost no one who uses HMR with React seems to realize. The difficulty of solving this problem in a general way is why these plugins often label themselves as EXPERIMENTAL.

@marioaks
Copy link
Author

Thanks for the quick response! I think I get your point that getting HMR to work well often requires some manual effort (especially when using experimental plugins), but Fast-Refresh is fully supported by React and should definitely be working out-of-the-box with Apollo Client. The ubiquity (borderline necessity) of HMR/FR means that any feature that doesn’t support it is going to have a hard time being adopted widely. If fast-refresh makes reactive variables no longer reactive, that seems to be a clear indication that there’s something wrong with the RV setup.

I’m a little new to all this, so take this somewhat with a grain of salt, but here are some things that could potentially be causing this issue:

  1. A fast-refresh triggers a re-run of all effects & all of the effect’s cleanups. If there is a cleanup handler that somehow disposes of makeVar’s reactivity, rerunning the effect after the cleanup might make our reactive variable... unreactive. The issue here would be in assuming that the cleanup only executes on unmount, when it actually also executes on a fast-refresh. If this is the problem, the fix would be to ensure that the logic that initially makes makeVar reactive is re-run.

  2. You wrote somewhere that a reactive variable that hasn’t been associated with any caches yet won’t trigger any broadcasts when updated and can just be used as a container. Is it possible that a Fast-Refresh is clearing all associations the variable has with any caches? That might explain why nothing seems to happens when I try to reset the variable after a fast-refresh.

I might totally be wrong about these, but since fast-refresh is getting more and more popular, I really believe that there’s something here that needs to be fixed. Thanks!

@gaearon
Copy link

gaearon commented Sep 8, 2020

Cross-referencing an explanation about how Fast Refresh works: #5870 (comment). Instead of a special API to "hook into" it I believe the fix is to handle the semantics of how it re-runs the Hooks.

@EarthlingDavey
Copy link

EarthlingDavey commented Nov 13, 2020

I found this issue because I'm using next.js with Apollo Client and reactive variables.
The cause of the issue was not obvious for me. Please allow me to add a phrase for others who might be searching.
Apollo reactive variables not working with next js - Fast Refresh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants