vishalbalaji / trpc-svelte-query-adapter

A simple adapter to use `@tanstack/svelte-query` with trpc, similar to `@trpc/react-query`.
71 stars 6 forks source link

Passing inputs to createServerQuery on the client-side #34

Closed smaven closed 3 months ago

smaven commented 4 months ago

Let's say I'm using createServerQuery to prefetch a list of users on the server and pass the query to the client:

// +page.ts
import type { PageLoad } from './$types';
import { trpc } from '$lib/trpc/client';

export const load: PageLoad = async (event) => {
  const { queryClient } = await event.parent();
  const client = trpc(event, queryClient);

  return {
    users: await client.user.all.createServerQuery(),
  };
};

I can use the query result to display content accordingly:

<!-- +page.svelte -->
<script lang="ts">
  import type { PageData } from './$types';

  export let data: PageData;

  const users = data.users();
</script>

<h1>List of users</h1>

{#if $users.isFetching}
  <p>Loading...</p>
{:else if $users.error}
  <p>Error: {$users.error.message}</p>
{:else if $users.isSuccess}
  <ul>
    {#each $users.data as user}
      <li>{user.name}</li>
    {/each}
  </ul>
{:else}
  <p>No users found</p>
{/if}

Now I want to filter the list of users as someone types in an input field. This requires me to send an input to the query. My guess was I would be able to pass the input to data.users() just like I can pass the input to trpc($page).user.all.createQuery(input) but this does not work and I could not find an example to achieve this.

<!-- +page.svelte -->
<script lang="ts">
  import type { PageData } from './$types';

  export let data: PageData;

  let filter = '';

  $: users = data.users({ name: filter });
</script>

<input type="text" bind:value={filter} placeholder="Filter users" />

...

I might be missing something really obvious here as this seems to me like a very common use case: fetching data on the server, passing it to the client so that the client doesn't have to load it again when it hydrates and then the subsequent loading of data happens on the client when inputs vary depending on user actions.

Apologies if this has been already answered somewhere, I dug into the README and issues but couldn't find anything.

vishalbalaji commented 4 months ago

@smaven Great catch! This is something I realized about a month ago, but I have been a bit busy with work lately and haven't been able to work on this lib all that much. Expect this to be fixed in the update.

vishalbalaji commented 3 months ago

Hi @smaven, thank you for opening this issue! This feature has been pushed and is available from v2.3.0 onward.

smaven commented 3 months ago

@vishalbalaji, I tried out the feature and I feel one thing is missing in the implementation. Currently, the query only re-runs if the input changes to a truthy value. I think the query should re-run whenever the input changes, no matter what its value is. Consider the following:

<!-- +page.svelte -->
<script lang="ts">
  import type { PageData } from './$types';

  export let data: PageData;

  let filter: string | null = 'foo';
  let switch = true;

  // input is `undefined` when no filter has been set. Query should still re-run.
  $: users = data.users(filter ? { name: filter } : undefined);

  // input is changed to `false`. Query should still re-run.
  $: status = data.status(switch)
</script>

<input type="text" bind:value={filter} placeholder="Filter users" />
<input type="checkbox" bind:checked={switch} />
...

The assumption is that the tRPC procedures can be configured to run with any input and the query should always re-run whenever the input changes even if the value is falsy.

Thanks for implementing this feature BTW! 🙌

vishalbalaji commented 3 months ago

@smaven Thanks for pointing this out! Fix has been pushed in v2.3.1.

smaven commented 3 months ago

@vishalbalaji I've noticed another issue:

  1. Consider a page loads that has the query created by createServerQuery and its inputs change.
  2. A network request is made when the inputs change.
  3. If the inputs change back to any of the previously set inputs, the query will not make a network request and instead fetches the results from cache.

Expected behaviour: The query should respect the stale time and make a network request if data is stale.

It works fine if I do a client-side navigation to a different page and then back to the page with the query. But does not work when the page first loads.

vishalbalaji commented 3 months ago

Hey @smaven, sorry for the late reply, have been a bit busy this past week.

I looked into this issue and its mainly happening because I am disabling refetchOnMount by default for the server query functions to prevent them re-running on the client.

So for now, if you are using staleTime, make sure to also set refetchOnMount to true for that query.