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

Changed return type of useMutation when ignoreResult is explicitly set to true to hide unset result #12277

Closed
wants to merge 2 commits into from

Conversation

Cellule
Copy link
Contributor

@Cellule Cellule commented Jan 15, 2025

We've encountered numerous bugs around this where the default (somehow) was to set ignoreResult: true when calling useMutation
Then devs would try to use data or loading from the tuple without realizing it would never be set.
I've been using this patch for a while and it does help avoid bugs

Copy link

changeset-bot bot commented Jan 15, 2025

🦋 Changeset detected

Latest commit: 185c889

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

Copy link

netlify bot commented Jan 15, 2025

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

Visit the deploys page to approve it

Name Link
🔨 Latest commit 185c889

@svc-apollo-docs
Copy link

svc-apollo-docs commented Jan 15, 2025

✅ Docs preview ready

The preview is ready to be viewed. View the preview

File Changes

0 new, 2 changed, 0 removed
* (developer-tools)/react/(latest)/development-testing/schema-driven-testing.mdx
* (developer-tools)/react/(latest)/development-testing/testing.mdx

Build ID: a6b98535a5473ca491c3f8c8

URL: https://www.apollographql.com/docs/deploy-preview/a6b98535a5473ca491c3f8c8

@Cellule Cellule force-pushed the useMutation-ignoreResults branch from ef8b036 to ac38202 Compare January 15, 2025 17:08
@jerelmiller
Copy link
Member

Hey @Cellule 👋

These are on my TODO list to review tomorrow (Friday). Just wanted you to know I saw these come in and will get to these very soon!

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.

This change is great and I do agree it should help prevent some crashes due to the types being wrong.

I had one minor change for accessing fields that are there at runtime even with ignoreResults: true. Once that is updated, I'd be happy to get this into the next release. Thanks for the contribution!

): [
MutationFunction<TData, TVariables, TContext, TCache>,
// result is not reliable when ignoreResults is true
Pick<MutationResult<TData>, "reset">,
Copy link
Member

Choose a reason for hiding this comment

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

It looks like we still return loading, called, and client properties even when ignoreResults are set. They just happen to use their initial values:

const [result, setResult] = React.useState<Omit<MutationResult, "reset">>({
called: false,
loading: false,
client,
});

Can we include those properties here as well? I see no reason not to be able to access them, even if loading or called never changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The biggest problem I've seen is that while the properties are there at runtime, their value is always unset.
Trying to use them is almost sure to be a bug.

In my opinion, I feel that at runtime the unreliable fields should not be returned, but that would be breaking change and I wasn't keen on going down that route.
Even changing the type has the potential to cause typescript errors after update, but it should in theory find potential bugs in the code.

I see that client is potentially correct IF not provided when calling the mutation

Now that I review it a bit more, I now notice that in the catch case it'll actually set the result to have an error
But if the mutation is called another time and succeeds, the error won't be cleared in the result making it even more unreliable

Copy link
Member

Choose a reason for hiding this comment

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

We've got a planning meeting tomorrow so let me take this to the team and get their thoughts on this.

// TODO This FetchResult<TData> seems strange here, as opposed to an
// ApolloQueryResult<TData>
) => Promise<FetchResult<MaybeMasked<TData>>>,
mutate: MutationFunction<TData, TVariables, TContext, TCache>,
Copy link
Member

Choose a reason for hiding this comment

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

💯 I have no idea why this wasn't that way to begin with. Good find!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hahah yeah, I went down the route of making a new type... only to realize it already existed 😅

expectTypeOf(result).toMatchTypeOf<{ reset: () => void }>();
expectTypeOf(result).not.toMatchTypeOf<MutationResult<Mutation>>();
expectTypeOf(mutate()).toMatchTypeOf<Promise<FetchResult<Mutation>>>();
const {
Copy link
Member

Choose a reason for hiding this comment

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

Can you update this to check client and called as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, I rewrote it a bit, the destructuring was not needed and made the test longer than needed

@jerelmiller
Copy link
Member

@Cellule we met as a team and discussed this change a bit more.

The more we talked, the more we questioned why ignoreResults made any sense at all. In summary:

  • This hook is not affected by cache updates.
  • Rerenders only take place when you call the mutate function.
  • You can use client.mutate directly (along with useApolloClient to get access to the client) to achieve this same behavior.

What we'd like to do instead is deprecate this option and remove it in v4. Would you be willing to update this PR to mark this field as @deprecated? I'd love to get that change in our upcoming 3.13 release.

@Cellule
Copy link
Contributor Author

Cellule commented Jan 22, 2025

@Cellule we met as a team and discussed this change a bit more.

The more we talked, the more we questioned why ignoreResults made any sense at all. In summary:

  • This hook is not affected by cache updates.
  • Rerenders only take place when you call the mutate function.
  • You can use client.mutate directly (along with useApolloClient to get access to the client) to achieve this same behavior.

What we'd like to do instead is deprecate this option and remove it in v4. Would you be willing to update this PR to mark this field as @deprecated? I'd love to get that change in our upcoming 3.13 release.

I'm all up for that!
I've slowly started to change our default way of doing things to stop passing ignoreResults since it is more likely to cause confusions than anything.
I'll update my PR

@Cellule
Copy link
Contributor Author

Cellule commented Jan 22, 2025

actually, I'll just close this PR and open a new one since there's really nothing shared between the 2

@Cellule Cellule closed this Jan 22, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 22, 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.

3 participants