SvelteStack / svelte-query

Performant and powerful remote data synchronization for Svelte
https://sveltequery.vercel.app
MIT License
822 stars 30 forks source link

svelte-query randomly runs the query server-side, and returns an empty result with 'success' status #80

Open benwoodward opened 2 years ago

benwoodward commented 2 years ago

I have this confusing issue with svelte-query 1.6.0, @sveltejs/kit 1.0.0-next.295, and svelte 3.46.4.

Occasionally, svelte-query will seemingly at random run the query server-side, and returns an empty result with 'success' status.

This query usually works, and if this error happens, I can just open the URL in a new tab and it works fine.

Error:

500
Cannot read property 'muxVideo' of null
TypeError: Cannot read property 'muxVideo' of null
    at [slug].svelte:98:63
    at Object.$$render (/Users/ben/dev/my-project/node_modules/svelte/internal/index.js:1745:22)
    at Object.default (root.svelte:50:47)
    at Object.default (/src/routes/__layout.svelte:187:36)
    at eval (/node_modules/@sveltestack/svelte-query/svelte/queryClientProvider/QueryClientProvider.svelte:38:41)
    at Object.$$render (/Users/ben/dev/my-project/node_modules/svelte/internal/index.js:1745:22)
    at __layout.svelte:106:29
    at Object.$$render (/Users/ben/dev/my-project/node_modules/svelte/internal/index.js:1745:22)
    at root.svelte:38:45
    at $$render (/Users/ben/dev/my-project/node_modules/svelte/internal/index.js:1745:22)

If I log the query result, I get this in the backend logs:

[watch:svelte] {
[watch:svelte]   status: 'success',
[watch:svelte]   isLoading: false,
[watch:svelte]   isSuccess: true,
[watch:svelte]   isError: false,
[watch:svelte]   isIdle: false,
[watch:svelte]   data: { getTranscript: null },
[watch:svelte]   dataUpdatedAt: 1647253771588,
[watch:svelte]   error: null,
[watch:svelte]   errorUpdatedAt: 0,
[watch:svelte]   failureCount: 0,
[watch:svelte]   isFetched: true,
[watch:svelte]   isFetchedAfterMount: false,
[watch:svelte]   isFetching: false,
[watch:svelte]   isRefetching: false,
[watch:svelte]   isLoadingError: false,
[watch:svelte]   isPlaceholderData: false,
[watch:svelte]   isPreviousData: false,
[watch:svelte]   isRefetchError: false,
[watch:svelte]   isStale: false,
[watch:svelte]   refetch: [Function: bound refetch],
[watch:svelte]   remove: [Function: bound remove]
[watch:svelte] }

My component:

<script context="module">
  /**
   * @type {import('@sveltejs/kit').Load}
   */
  export async function load({ params, fetch, session, context }) {
    return {
      props: {
        slug: `${params.slug}`
      }
    };
  }
</script>

<script>
  // deps
  import '$lib/polyfills';
  import { setContext, getContext } from 'svelte';
  import { writable } from 'svelte/store';
  import { useQuery, useInfiniteQuery } from '@sveltestack/svelte-query';

  // queries
  import { TranscriptBySlugDocument } from '$lib/graphql/queries/types/transcripts';

  export let slug;

  const graphQLClient = getContext('graphql-client');

  let params = writable({ slug });
  setContext('params', params);
  $: $params.slug = slug;

  const getTranscript = async () => {
    return await $graphQLClient.request(TranscriptBySlugDocument, { slug: $params.slug });
  };

  const transcriptQuery = useQuery('transcriptQuery', getTranscript, {
    enabled: false
  });

  $: if ($graphQLClient?.fetchOptions?.headers?.['X-Auth-Token'] !== undefined) {
    transcriptQuery.setEnabled(true);
  }
  setContext('transcriptQuery', transcriptQuery);

  $: console.log($transcriptQuery)
</script>

<div class="grid grid-cols-12 gap-3 leading-6 text-gray-700">
  <div class="col-span-4 p-3 leading-6 text-gray-700">
    {#if $transcriptQuery.isLoading || $transcriptQuery.isIdle}
      <span>Loading..</span>
    {:else if $transcriptQuery.isSuccess}
      <div class="video-container" style="min-height: {videoContainerHeight}">
        <TranscriptVideo
          videoId={$transcriptQuery.data.getTranscript.muxVideo.playbackId}
          playerType='hls' />
      </div>
    {:else}
      <span>Error loading video</span>
    {/if}
  </div>
</div>

__layout.svelte:

<script>
  const graphQLClientStore = writable(graphQLClient);
  fetchToken();
  setContext('graphql-client', graphQLClientStore);

  async function fetchToken() {
    // XXX: Temp workaround due to:
    // https://github.com/sveltejs/kit/issues/1198
    //
    // Also see:
    // https://github.com/sveltejs/kit/issues/696
    // https://github.com/sveltejs/kit/issues/672
    //
    // Until this is resolved, useQueryClient cannot
    // be used because we need to reactively update
    // the client with the token after the app has
    // initialised. useQueryClient doesn't allow this
    const userAuth = await fetch('/api/auth/user');
    const tokens = await userAuth.json();
    const jwt = tokens.jwt;

    $graphQLClientStore.setFetchOptions({
      headers: {
        'X-Auth-Token': jwt
      }
    });

    // Trigger reactive update
    $graphQLClientStore = $graphQLClientStore;
  }

  onMount(async () => {
    fetchToken();
  });
</script>