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

Deprecate ignoreResults in useMutation #12296

Merged

Conversation

Cellule
Copy link
Contributor

@Cellule Cellule commented Jan 22, 2025

From discussion in #12277
ignoreResults is more likely to cause confusion than actually help since the results are always returned.
The option potentially reduces the number of rerenders where the mutation is hooked, but I'm skeptical of the necessity and effectiveness of this.
If there's really a need for performance around state management in useMutation then there could be a separate hook more specialized for this that has a clear contract and expected behavior instead of a somewhat unused state that doesn't always gets refreshed

@jerelmiller I was wondering if we want to also deprecate ignoreResults in useSubscription. I admit I didn't even know that was an option there so I didn't dig

Copy link

netlify bot commented Jan 22, 2025

👷 Deploy request for apollo-client-docs pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 13dc2f6

Copy link

changeset-bot bot commented Jan 22, 2025

🦋 Changeset detected

Latest commit: 13dc2f6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@apollo/client Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@svc-apollo-docs
Copy link

svc-apollo-docs commented Jan 22, 2025

⚠️ Docs preview not attached to branch

The preview was not built because the PR's base branch release-3.13 is not in the list of sources.

An Apollo team member can comment one of the following commands to dictate which branch to attach the preview to:

  • !docs set-base-branch version-2.6
  • !docs set-base-branch main

Build ID: cf5f6b966b3da7413a0e7f8e

@jerelmiller
Copy link
Member

@Cellule we want to keep the ignoreResults in useSubscription as that one makes a lot more sense. That hook has a much higher likelyhood that it may update very often if subscription events come in very quickly. In this case, sometimes you don't want/need the rerender behavior, especially if you're using those subscriptions to do something like logging. In that case, you may prefer to use the callbacks.

That option was added to useSubscription in 3.11 via #11921. #10216 provides some great context on what problem that change solved if you're curious on learning more (be sure to check out the linked articles in the issue.)

@jerelmiller jerelmiller changed the base branch from main to release-3.13 January 22, 2025 20:45
@jerelmiller jerelmiller requested a review from a team as a code owner January 22, 2025 20:45
@Cellule
Copy link
Contributor Author

Cellule commented Jan 22, 2025

@Cellule we want to keep the ignoreResults in useSubscription as that one makes a lot more sense. That hook has a much higher likelyhood that it may update very often if subscription events come in very quickly. In this case, sometimes you don't want/need the rerender behavior, especially if you're using those subscriptions to do something like logging. In that case, you may prefer to use the callbacks.

That option was added to useSubscription in 3.11 via #11921. #10216 provides some great context on what problem that change solved if you're curious on learning more (be sure to check out the linked articles in the issue.)

Thanks for the details! It does make a lot of sense.
We're slowly starting to migrate away from subscribeToMore in favor of useSubscription. The query update mechanism is not as easy/clean, but it works great
I'll definitely look into ignoreResults in useSubscription

@jerelmiller
Copy link
Member

Oops, I repointed this branch to our 3.13 release before I merged the latest from main into that one. Do you mind rebasing this against the release-3.13 branch?

@jerelmiller jerelmiller requested review from jerelmiller and removed request for a team January 22, 2025 20:57
@Cellule Cellule force-pushed the deprecated-ignoreResults branch from 9c368a0 to b844568 Compare January 22, 2025 21:06
@Cellule Cellule force-pushed the deprecated-ignoreResults branch from b844568 to 13dc2f6 Compare January 22, 2025 21:07
Copy link
Member

@jerelmiller jerelmiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent. Thanks for doing this!

@jerelmiller jerelmiller merged commit 2422df2 into apollographql:release-3.13 Jan 22, 2025
30 of 31 checks passed
@phryneas
Copy link
Member

phryneas commented Jan 23, 2025

As for useSubscription, I also want to give another angle: it makes sense as a hook, even with the option.

What do I mean by that?

Hooks are mostly defined by the fact that they call a React hook. That means they need to do one of the following:

  1. dependency injection - access context
  2. synchronize with the lifecycle of a component (mount, unmount etc) - useEffect etc.
  3. inject something happen outside the component (user interaction, subscriptions) into the component - useState

useMutation without ignoreResults does 1. and 3. - but as soon as you add ignoreResults, 3. goes away and you're left with 1. useApolloClient does that already. There's no need for useMutation in that case anymore.

useSubscription without ignoreResults does 1., 2., and 3., - and as soon as you add ignoreResults, 3. goes away, but 1. and 2. stays

useSubscription with ignoreResults is still useful because it synchronizes an external system with the component lifecyclye: once the component mounts, the subscription starts - when it unmounts, it unsubscribes. You can't do that without a hook and also not with one of the other hooks we provide.

/** {@inheritDoc @apollo/client!MutationOptionsDocumentation#ignoreResults:member} */
/**
* {@inheritDoc @apollo/client!MutationOptionsDocumentation#ignoreResults:member}
* @deprecated This property will be removed in the next major version of Apollo Client
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add a bit more information what to use instead?

"Instead, please use useApolloClient to get your ApolloClient instance and call client.mutate directly."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I wonder is, if there's really a good reason to have an optimized version of mutate that doesn't hook into the lifecycle.
Maybe we'd want to offer a helper to do that.
Something like useMutate (I'm bad with naming things...) that would very simply take a mutation document, maybe an optional client and return a useCallback wrapper around client.mutate
That would simplify the implementation and make a clear distinction between cases where you might want to use data, loading state or some other information about the mutation through useMutation and a more lightweight version that won't cause a rerender when the mutation is called.

I'd wait to hear community feedback before implementing such helper, but I agree maybe there should be a bit more details in the deprecation notice

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really argue "this shouldn't be a hook" and "people shouldn't be afraid just touching the client" here.

One thing I wonder is, if there's really a good reason to have an optimized version of mutate that doesn't hook into the lifecycle.

I mean, you have used it in a good number of places, so there seems to be demand to at least do this from time to time? :D

I could see places where you might want to just trigger a bunch of mutations and are really not interested in the result, and it might be so many mutations that you would get a performance problem from the resulting renders. That said, I would also say that these places would not be the root problem, and instead those "expensive renders" would need investigating, - but that doesn't mean that the use case doesn't exist.

And it's certainly nothing we'd encourage, as, as I said, the root of the problem usually would be a performance problem somewhere else - and as it can be done without a hook I'd just not provide such a hook.

maybe there should be a bit more details in the deprecation notice

Could you open a follow-up PR? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, you have used it in a good number of places, so there seems to be demand to at least do this from time to time? :D

To be fair, it was used like a default way of doing things which lead to numerous bugs and confusion.
A lot of devs would have a separate state to track the loading state and try to update it manually instead of simply using const [mutate, { loading }] = useMutation()

Could you open a follow-up PR? :)

Looking into it right now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #12301 we can continue the discussion there :)

@Cellule
Copy link
Contributor Author

Cellule commented Jan 23, 2025

useSubscription with ignoreResults is still useful because it synchronizes an external system with the component lifecyclye: once the component mounts, the subscription starts - when it unmounts, it unsubscribes. You can't do that without a hook and also not with one of the other hooks we provide.

Really good explanation of the difference between both use cases!

@github-actions github-actions bot mentioned this pull request Feb 3, 2025
@github-actions github-actions bot mentioned this pull request Feb 13, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 23, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants