#Can you use useFetch twice in one composable, once on server, once in client?

23 messages · Page 1 of 1 (latest)

gray crane
#

I am trying to use useFetch() once on the server and a second time in the client, in one composable.
So far I have not been able to get this to work.

A reproduction of my attempt can be found here: https://stackblitz.com/edit/github-o9ivmk?file=composables%2FuseTwoStepFetch.ts
It is the second useFetch() with server:false that I cannot get to return something -- it always returns null.
Is there a way to get this working? An example somewhere?

The composable looks like this:

// Simplified example.
// Fetch data in two steps:
// 1. Quickly get a small number of records (3)
// 2. Get all the rest of the data
export async function useTwoStepFetch() {
  const nuxtApp = useNuxtApp();
  const result = ref([] as any[]);

  // get the first 3 records
  // use useFetch() so this call can be done on the server
  const body1 = { take: 3 };
  await nuxtApp.runWithContext(async () => {
    const { data }: any = await useFetch('/api/hello', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: body1,
      watch: false,
      server: true,
      lazy: false,
    });

    // Put data in the result
    console.log('data.value (1)', data.value);
    result.value = data.value;
  });

  // get the rest of the data
  // ** HERE I WANT TO BE SURE THAT IT RUNS ONLY ON CLIENT **
  const body2 = { skip: 3 };
  // ** NO AWAIT BECAUSE WE WANT TO RETURN THE RESULT BEFORE THE CALL FINISHED **
  nuxtApp.runWithContext(async () => {
    const { data }: any = await useFetch('/api/hello', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: body2,
      watch: false,
      /* server:true, lazy:false works, but that is not what I want */
      server: false,
      lazy: true,
    });

    console.log('data.value (2)', data.value);
    result.value.splice(result.value.length, 0, ...(data.value || []));
  });

  return result;
}

Create a new Nuxt project, module, layer or start from a theme with our collection of starters.

pastel shale
#

you're trying to access the data before it is ready

gray crane
#

I guess you are right in that, but I don't really understand how to do it different.
Isn't the await (before the second useFetch() making sure that we are waiting until the data is ready?

I try to have the first part of my composable to take place on the server and the second part to take place on the client.
I also tried hooks, but to no avail yet.

pastel shale
#

you can't use lazy and then try and access data.value right away

gray crane
#

Ah, I'll have to read about lazy in the documentation once again then.
Thank you so much for taking time to answer.

pastel shale
#

you'll either want to use a watch or interceptors (onResponse) with $fetch, and update result's value in one of those handlers

gray crane
#

I'll have to make a study about this.
I see the change you made, but it will need some time for me to understand 😅 .

pastel shale
#

but doing this with lazy: result.value.splice(result.value.length, 0, ...(data.value || [])); uses the data.value at that very moment, and will not update when the lazy api call completes

gray crane
#

Actually your example also has lazy:true same as mine -- or am I looking at the wrong place?

#

Oh, wait, you are using $fetch -- but then, can I be sure this will only be run in the client?

#

$fetch doesn't deduplicate so the call could potentially happen both on the server and in the client, which I don't want.

pastel shale
#

i only looked at the null issue, not anything else - let me see

gray crane
#

Oh, I think I'm getting at it.
If is set server:false, lazy:false for the second useFetch(), the useFetch() will be run twice (once on server, once on client), but the first (on server) returns "null" and the second (on client) return "[3,4,5,6,7,8,9]".

#

I think I'll be able to get this working in the non-simplified version at work :-).

pastel shale
#

that's not going to do what you want though

gray crane
#

Oh, is seems to do it for me.
What is wrong do you think?

pastel shale
#

you're still trying to access the data.value before it is ready

gray crane
#

When I click the refresh-button I first see "[0,1,2]" (which I think is rendered on the server) and after a fraction of a second this is changed to "[0,1,2,3,4,5,6,7,8,9]", so it seems to work.

#

I changed "lazy:true" to "lazy:false", zo the data is ready right away as I understand it.

pastel shale
#

oh you changed lazy to false

gray crane
#

:-).