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

Add ability to easily update query cache #390

Open
nickzelei opened this issue Jul 12, 2024 · 5 comments
Open

Add ability to easily update query cache #390

nickzelei opened this issue Jul 12, 2024 · 5 comments

Comments

@nickzelei
Copy link

Hey all, awesome project! This is allowing me to easily switch away from swr over to using tanstack/query.

One thing I miss however is the ability to easily update the query cache.

With swr, each instance has a mutate function that includes the curried key, so I can easily pass it the new value.
With the current iteration of this library, the refetch function that is returned from useQuery takes no parameters.

In order for me to update the underlying cache, I have to do something like this:

const queryclient = useQueryClient();
const { mutateAsync } = useMutation(createMyValue);

async function onSubmit(values: MyFormValues): Promise<void> {
  const resp = await mutateAsync(...values...);
  queryclient.setQueryData(
    createConnectQueryKey(geyMyValue, {
      id: resp.myvalue.id,
    }),
    new GetMyValueResponse({
      myvalue: resp.myvalue,
    })
  );
}

I'd love it if there were an easier way to trigger a cache update for a useQuery value that didn't involve so much boilerplate.

@timostamm
Copy link
Member

Thanks for the issue! In general, invalidating queries (triggering a refresh) instead of manipulating the cache is preferable because it's so simple and reliable (for example, you'll never forget to also update a lastUpdated property).

For example, I've often seen a pattern like this:

  const res = useMutation(createMyValue, {
    onSuccess: (data) =>
      queryClient.invalidateQueries({
        queryKey: createConnectQueryKey(geyMyValue, {
          id: data.id,
        }),
      })
  });

I'm not closely familiar with swr. Is it more common to update the cache than to let it update?

@nickzelei
Copy link
Author

Thanks for the response! Unclear if it's more common or not to do that. swr works effectively the same way as the refetch does with their mutate, but they optionally allow you to provide a cache value.

Since our mutation APIs like Create, Update return the latest object, I like to optimistically update the cache because we have the latest object instead of just calling refetch again to hit the API one more time.

Perhaps this is an anti-patten and it's just way more common to simply call refetch or invalidate.

@timostamm
Copy link
Member

Since our mutation APIs like Create, Update return the latest object, I like to optimistically update the cache

I'm not sure I'd call it an anti-pattern, just that I would generally recommend to invalidate and refetch for simplicity. Makes perfect sense to me to not waste a roundtrip, if you know what you're doing 🙂

Here's the tanstack/query guide on this topic: https://tanstack.com/query/latest/docs/framework/react/guides/updates-from-mutation-responses

Maybe the most straight-forward improvement would be a function similar to this:

import {type Message, type PartialMessage,} from "@bufbuild/protobuf";
import {QueryClient} from "@tanstack/react-query";
import {createConnectQueryKey, type MethodUnaryDescriptor} from "@connectrpc/connect-query";

export function setQueryData<
  I extends Message<I>,
  O extends Message<O>,
>(
  client: QueryClient,
  methodDescriptor: Pick<MethodUnaryDescriptor<I, O>, "I" | "name" | "service">,
  input: PartialMessage<I>,
  output: O,
): void {
  const key = createConnectQueryKey<I, O>(methodDescriptor, input);
  client.setQueryData(key, output);
}

It just provides a bit of type-safety for RPCs on top of QueryClient.setQueryData. Maybe we can add it to the package if it works out well.

@paul-sachs
Copy link
Collaborator

Although I think we could make it a little easier with a custom QueryClient, we do have a helper method to handle these kinds of things: createProtobufSafeUpdater.

We've been internally playing with the idea of exporting a custom QueryClient that provides common helper methods for interacting with the query client in a typesafe way but that will probably wait till everything has been moved over to protobuf-es@v2 anyways.

@nickzelei
Copy link
Author

Thanks for the note @paul-sachs - I must have missed that function in the docs. Will have to go through my code and update the refs, that is very helpful!
Apologies for the comment delay, my github emails need to be reworked...
Saw that there is also more work happening in v2, which is exciting!

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

No branches or pull requests

3 participants