How to defer useFetch/useAsyncData properly with reactive body or options

The Nuxt3 useFetch and useAsyncData composables are really great. They allow us to fetch data in various scenarios and are widely customizable through all their options.

In an application we developped, we wanted to improve a form to display a loading status on the submit button when the request is performed against our API.
So here was the starting point of our component template and script setup:

<template>
    <input name="pseudo" v-model="pseudo" />

    <button @click="sendForm" />
</template>

<script setup>
    const pseudo = ref('')

    function sendForm() {
        const {data, error} = useFetch('api/register', {method: 'post', body: {pseudo}})
    }
</script>

The problem with this implementation is that we cannot use the status of our request returned by the useFetch composable to display it inside our template, because it only lives temporarily inside our sendForm function.

So the first step to get the status of our request was to "prepare" it at the root level and gets both the status and the execute handler to call it later.

<template>
    <input name="pseudo" v-model="pseudo" />

    <button @click="sendForm"
            <!-- Attaching a class to display the request pending status -->
            :class="{
                loading: status === 'pending'
            }"
    />
</template>

<script setup>
    const pseudo = ref('')

    //   Reactive status vvvv    vvv execute callback renamed to sendForm
    //                  vvvvvv  vvvvvv   vvvvvvvv
    const {data, error, status, execute: sendForm} = useFetch(
    'api/register', {
        method: 'post',
        body: {pseudo},
        // immediate option should be set to false to
        // disable the useFetch auto-execution
        // of the request on component setup
        immediate: false
    })
</script>

Now we can display our loading status, great!
But we still have a problem: the default behaviour of useFetch is to execute the request anytime a reactive property in the url or params is updated.

Due to that, anytime we update the pseudo, the form is sent, damn it!

Fortunately, useFetch and useAsyncData allow us to disable this feature just by passing the watch option to false.

<script setup>
    const pseudo = ref('')

    const {data, error, status, execute: sendForm} = useFetch(
    'api/register', {
        method: 'post',
        body: {pseudo},
        immediate: false,
        // Disable the auto-refreshing data when pseudo reactive updates
        watch: false
    })
</script>

Now we can achieve what we wanted: we can use both the status reactive inside our template to display a loading status on our submit button and attach the execute handler to the @click event to send the form only when the user needs it.

Comments

Be the first to post a comment!

Add a comment

Preview