Search code examples
nuxt.jshooknuxt3.js

How to prevent execution of useFetch in nuxt3 when body was changed


Scenario:

  1. There is login page.
  2. We want to send request to server ONLY when login button is pushed.
  3. We do not want to send request when user changed input.

This is my code:

const body = ref<{ identifier: string, password: string }>({
  identifier: '',
  password: ''
});

const {data, execute, error, pending} = await useFetch(`${config.public.baseUrl}/api/auth/local`, {
  body,
  lazy: true,
  method: 'post',
  immediate: false,
  watch: [],
})

async function login() {
  console.log("login");
  await execute();
}

and template

    <form @submit.prevent="login">
      <label for="email">
        Email
        <input type="text" v-model="body.identifier">
      </label>
      <label for="password">
        Password
        <input type="password" v-model="body.password">
      </label>

      <button>Login</button>
    </form>

unfortunately even if I do not click button this form will send post request to /api/auth/local every time when user type letter in this form.

This behavior is described in documentation:

https://nuxt.com/docs/api/composables/use-fetch

All fetch options can be given a computed or ref value. These will be watched and new requests made automatically with any new values if they are updated.

I need to override this feature.

Change of

v-model

to

v-model.lazy

helps a little bit, but I still can't control exact time when this request is send.


My current workaround

const body = ref<{ identifier: string, password: string }>({
  identifier: 'user@ok.com',
  password: ''
});

const loginBody = ref<{ identifier: string, password: string }>({
  identifier: '',
  password: ''
});

const {data, execute, error, pending} = await useFetch(`${config.public.baseUrl}/api/auth/local`, {
  body: loginBody,
  lazy: true,
  method: 'post',
  immediate: false,
  watch: [],
})

async function login() {
  console.log("login");
  loginBody.value = body.value;
  await execute();
}

is not enough good, because it sends actually 2 requests in the same time, but first is immediately cancelled.


Solution

  • Finally i achieved my goal writing function

    async function login() {
      if(JSON.stringify(loginBody.value) === JSON.stringify(body.value)) {
        await execute();
      } else {
        loginBody.value = body.value;
      }
    }
    

    Request is executed once always when login function is called. It body changed his value, then assign to loginBody triggers request. In other case we executing is manually by execute.

    Little over-engineered but works.