Skip to content

Add setData method to Query object for simpler cache updates #62

@vlashada

Description

@vlashada

When handling mutations that return data used in existing queries, developers currently have two options:

  1. Trigger a full query refetch
  2. Manually update the query cache

Manual cache updates require accessing the queryClient and using setQueryData with hand-constructed query keys. This approach:

  • Creates unnecessary complexity
  • Increases potential for errors in key construction
  • Reduces type safety
  • Results in verbose, hard-to-maintain code

I think this is sometimes referred to as optimistic updates.

Proposed Solution

Add a setData method directly to the Query object, allowing developers to update query data without manually managing query keys or accessing the query client.

Current Implementation

<script lang="ts">
  import { trpc } from "$src/lib/trpcClient";
  import { getQueryKey } from "trpc-svelte-query-adapter";
  import { useQueryClient } from "@tanstack/svelte-query";
  import { writable } from "svelte/store";

  const name = writable("John Doe");
  const userQuery = trpc().user.getInfo;
  const user = userQuery.createQuery(name);
  const queryClient = useQueryClient();

  const createGreeting = trpc().user.setAge.createMutation({
    onSuccess: (data) => {
      queryClient.setQueryData(
        getQueryKey(userQuery, name, "query"),
        (old: unknown) => {
          if (typeof old !== "object") return old;
          return { ...old, age: data.age };
        }
      );
    },
  });
</script>

<input bind:value={$name} />
<button onclick={() => $createGreeting.mutateAsync({ age: $user.age + 1 })}>
  Birthday
</button>
<p>{$user.age}</p>

Proposed Implementation

const createGreeting = trpc().user.setAge.createMutation({
  onSuccess: (data) => {
    user.setData(name, (old) => {
      if (typeof old !== "object") return old;
      return { ...old, age: data.age };
    });
  },
});

Benefits

Developer Experience

  1. More intuitive API that aligns with developer expectations
  2. Significantly reduces boilerplate code
  3. Eliminates need to manually construct and manage query keys
  4. Keeps related functionality (query data and its updates) together

Type Safety & Reliability

  1. Better TypeScript inference since the query's data type is already known
  2. Reduces potential runtime errors from incorrect key construction
  3. Makes code more maintainable and easier to refactor

Performance

  1. No performance overhead compared to current approach
  2. Still allows for granular cache updates without full refetches

Implementation Details

The setData method would internally:

  1. Access the query client
  2. Construct the appropriate query key
  3. Update the cache with the provided data

This encapsulation ensures consistency and reduces the chance of errors while maintaining all existing functionality.

Migration Path

This addition would be fully backward compatible, allowing developers to gradually migrate existing code while maintaining support for the current approach.

(i won't have time to work on this, just flagging that it would be nice to have)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions