Giter VIP home page Giter VIP logo

Comments (6)

jerelmiller avatar jerelmiller commented on May 26, 2024

Hey @jbachhardie 👋

This is an interesting! Playing around a bit more with your reproduction, I'm actually not sure this is an issue with useSuspenseQuery as much as it is the way the app is handling the error boundaries. I can actually reproduce the same situation with useQuery if I throw the error returned from the hook in the component. See my fork of the reproduction to see this behavior.

Digging in, there are a few things I noticed here though:

The route components are never rendered again once the error occurs. While the error message is properly updated in the UI according to the route you're on, the route component functions aren't called again. I added console.logs to the top of the two route components (App and OtherPage) and notice that neither of these are logged after the error occurs, regardless of how many times I switch the page.

This led me to think that the ErrorBoundary component isn't getting unmounted when you switch between the routes, which means the this.state.fallback is maintained and the error fallback is shown instead. I can confirm this to be the case. Adding a console.log inside componentWillUnmount in the error boundary shows that the component never actually unmounts. This would explain why it seems the two route components are stuck in the same state.

I'm able to fix the issue by adding a key prop to the Suspense boundary for the component passed to the Route element prop and adding a queryKey option to each useSuspenseQuery (see below for the technical reasons for this). Adding these two things makes the app work as you'd expect.

I added some comments in my fork for you to follow if you want to see this working as you'd expect.


Feel free to skip this section unless you're interested in some of the behind the scenes technical reason why queryKey is needed for this particular reproduction. This may only apply to your situation if you're using the same query across two different route components.

Just a note on why the queryKey is necessary here. Both of these components are using useSuspenseQuery with the same query/variables combination. Due to the mechanics of Suspense, we have a cache behind the scenes that ensures we can look up the request again after the component finishes loading. We use a combination of query and variables as the cache key in order to look this request back up. While you aren't technically using the same query in two different components that are mounted at the same time (the usual use case for queryKey), there is a catch to why this is needed in this particular situation.

In order to avoid issues with React.StrictMode, we remove the cache entry on component unmount asynchronously. We rely on useEffect for some implementation reasons, and useEffect runs twice in strict mode. This would mean that without the async cache eviction, we would accidentally remove the suspense cache entry too early. I believe what you're seeing in this particular reproduction is just the timing between the mount of one route component that happens before the cache removal is run, which means the 2nd route component ends up retaining the same cache entry.

Just as an FYI, we have a section on our docs for query call to call this out in case you needed a reference to it 🙂.


I'm not sure there is actually anything for us to do here. Please let me know if I've missed something. Hope this helps!

from apollo-client.

jerelmiller avatar jerelmiller commented on May 26, 2024

I should have also mentioned, you can use the errorPolicy option if you need to tweak how errors are handled inside useSuspenseQuery. The default value is none which means that errors are thrown to the nearest error boundary. If you prefer the useQuery style error property, you can set errorPolicy to all. This is technically meant to be used when you want to show partial data alongside your errors, but you can also use it to avoid the throw.

See the error handling section in our suspense docs for more information on this.

from apollo-client.

jbachhardie avatar jbachhardie commented on May 26, 2024

Hey, thank you so much for the thorough reply. I went back and made another attempt at reproduction that more closely zoomed in on the issue and directly compared suspense and non-suspense versions. I discovered that in fact useSuspenseQuery behaves exactly as expected and the same as useQuery so there's no issue here. The issue I'm seeing in my app and test setup must be specific to the conditions there and not due to useSuspenseQuery and I just messed up my initial reproduction.

Sorry for the bother but happy to have confirmed this all works as intended and that our approach to error handling with Suspense wasn't misguided.

from apollo-client.

github-actions avatar github-actions commented on May 26, 2024

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.

from apollo-client.

jerelmiller avatar jerelmiller commented on May 26, 2024

No problem at all! Glad to hear everything is working as expected 🙂

from apollo-client.

github-actions avatar github-actions commented on May 26, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
For general questions, we recommend using StackOverflow or our discord server.

from apollo-client.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.