nuxt: useFetch refresh not working when params change

Environment

Nuxt CLI v3.0.0-rc.4 18:15:14 RootDir: /Users/samedwardes/git/embeddedapp/webapp-frontend 18:15:15 Nuxt project info: 18:15:15


  • Operating System: Darwin
  • Node Version: v18.2.0
  • Nuxt Version: 3.0.0-rc.4
  • Package Manager: npm@8.9.0
  • Builder: vite
  • User Config: modules, runtimeConfig
  • Runtime Modules: @nuxtjs/tailwindcss@5.1.2, @formkit/nuxt@1.0.0-beta.8
  • Build Modules: -

πŸ‘‰ Report an issue: https://github.com/nuxt/framework/issues/new 18:15:15

πŸ‘‰ Suggest an improvement: https://github.com/nuxt/framework/discussions/new

πŸ‘‰ Read documentation: https://v3.nuxtjs.org

Reproduction

The example from the docs works.

<script setup>
const page = ref(1);

const { data: users, pending, refresh, error } = await useFetch(() => `users?page=${page.value}&take=6`, { baseURL: config.API_BASE_URL }
);

function previous(){
  page.value--;
  refresh();
}

function next() {
  page.value++;
  refresh();
}
</script>

When I pass page into the params option it does not work.

<script setup>
const page = ref(1);

const { data: users, pending, refresh, error } = await useFetch(() => `users`, {
  baseURL: config.API_BASE_URL ,
  params: { 
    page: page.value,
    take: 6
  }
}
);

function previous(){
  page.value--;
  refresh();
}

function next() {
  page.value++;
  refresh();
}
</script>

The API is still called again, but always with page set to a value of 1.

Describe the bug

The API is still called again, but always with page set to a value of 1.

Additional context

Is this expected behaviour, or is this a bug?

Logs

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 11
  • Comments: 18 (4 by maintainers)

Commits related to this issue

Most upvoted comments

there should be a way to automaticaly refetch based on a reactive search params this is already the current behevior with the first parameter of usefetch even refresh() does not provide a way to inject new params

what is the purpose of the watch option if the refresh will not catch new values ?

I just wanted to close the loop on this for future readers. I was able to get my desired behaviour with a single file component that looks like this:

<!-- app.vue -->

<template>
  <div>
    <div>Type a name below to get the predicted age:</div>
    <input type="text" v-model="name" />
    <div>Selected name is: {{ name }}</div>
    <div>Predicted age is: {{ age }}</div>
  </div>
</template>

<script setup>
const name = ref('sam');

const { data: age } = await useAsyncData(
  'age',
  () => $fetch('https://api.agify.io', {
    params: {
      name: name.value,
    },
  }),
  { watch: [name] }
);
</script>

Despite being an older issue, I want to propose a different approach here that still leveragesuseFetch. By passing a computed as any of the top-level option arguments, you can achieve the same:

Instead of:

const name = ref('sam');

const { data: age } = await useAsyncData(
  'age',
  () => $fetch('https://api.agify.io', {
    params: {
      name: name.value,
    },
  }),
  { watch: [name] }
);

You can write the following and achieve the same.

const name = ref('sam');
const params = computed(() => { name: name.value })

const { data: age } = await useFetch('https://api.agify.io', { params })

This is how Vue reactivity works - the value is frozen in time when you call useFetch: see https://github.com/nuxt/nuxt.js/issues/13982. If you want to keep it reactive, you can use useAsyncData and provide a custom fetcher function. Something like this: https://stackblitz.com/edit/github-c4jssa.

@mukundshah Yes - a desired side effect: Whenever the params (here the name) change, the API will be called again.

Despite being an older issue, I want to propose a different approach here that still leveragesuseFetch. By passing a computed as any of the top-level option arguments, you can achieve the same:

Instead of:

const name = ref(β€˜sam’);

const { data: age } = await useAsyncData(

β€˜age’,

() => $fetch(β€˜https://api.agify.io’, {

params: {
  name: name.value,
},

}),

{ watch: [name] }

);

You can write the following and achieve the same.


const name = ref('sam');

const params = computed(() => { name: name.value })



const { data: age } = await useFetch('https://api.agify.io', { params })

This is interesting. Why do you not need to use watch anymore when you use computed?

Despite being an older issue, I want to propose a different approach here that still leveragesuseFetch. By passing a computed as any of the top-level option arguments, you can achieve the same: Instead of:

const name = ref('sam');

const { data: age } = await useAsyncData(
  'age',
  () => $fetch('https://api.agify.io', {
    params: {
      name: name.value,
    },
  }),
  { watch: [name] }
);

You can write the following and achieve the same.

const name = ref('sam');
const params = computed(() => { name: name.value })

const { data: age } = await useFetch('https://api.agify.io', { params })

Looks like the refresh also works without computed and watcher. Just reference the ref object directly instead of the .value. Anything wrong with this?

const page = ref(1);
const { data: todos } = await useFetch( () => `https://jsonplaceholder.typicode.com/todos`, {
    params: {
      _page: page, // page.value will not update. But page does, even without a watcher
    },
  }
);

Thank you @manniL !

I just wanted to clarify for any other people who might still struggle. It’s important to utilise the params field rather than string interpolation on the url directly, or it won’t work πŸ˜ƒ

Despite being an older issue, I want to propose a different approach here that still leveragesuseFetch. By passing a computed as any of the top-level option arguments, you can achieve the same:

Instead of:

const name = ref('sam');

const { data: age } = await useAsyncData(
  'age',
  () => $fetch('https://api.agify.io', {
    params: {
      name: name.value,
    },
  }),
  { watch: [name] }
);

You can write the following and achieve the same.

const name = ref('sam');
const params = computed(() => { name: name.value })

const { data: age } = await useFetch('https://api.agify.io', { params })

Looks like the refresh also works without computed and watcher. Just reference the ref object directly instead of the .value. Anything wrong with this?

const page = ref(1);
const { data: todos } = await useFetch( () => `https://jsonplaceholder.typicode.com/todos`, {
    params: {
      _page: page, // page.value will not update. But page does, even without a watcher
    },
  }
);

Despite being an older issue, I want to propose a different approach here that still leveragesuseFetch. By passing a computed as any of the top-level option arguments, you can achieve the same:

Instead of:

const name = ref('sam');

const { data: age } = await useAsyncData(
  'age',
  () => $fetch('https://api.agify.io', {
    params: {
      name: name.value,
    },
  }),
  { watch: [name] }
);

You can write the following and achieve the same.

const name = ref('sam');
const params = computed(() => { name: name.value })

const { data: age } = await useFetch('https://api.agify.io', { params })

@manniL @danielroe is this approach safe? will it have any side effect?