Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як зробити асинхронну перевірку поля з затримкою й скасуванням застарілих запитів у Vue?

Задача: при реєстрації показати «цей email уже зайнятий» ще до відправки форми. Наївне рішення - запит на кожен введений символ - створює три проблеми:

  • навантаження: 20 символів - 20 запитів;
  • гонка відповідей: відповідь на olena@ може прийти пізніше за відповідь на olena@example.com, і на екрані залишиться неправильний результат;
  • перевірка незавершеного значення - марна робота.

Рішення - затримка + скасування + перевірка формату:

import { ref, watch, onWatcherCleanup } from 'vue'

const email = ref('')
const status = ref<'idle' | 'checking' | 'free' | 'taken' | 'error'>('idle')

watch(email, (value) => {
  if (!/^\S+@\S+\.\S+$/.test(value)) {
    status.value = 'idle'
    return
  }

  const controller = new AbortController()
  const timer = setTimeout(async () => {
    status.value = 'checking'
    try {
      const res = await fetch(`/api/email-available?email=${encodeURIComponent(value)}`, {
        signal: controller.signal,
        headers: { Accept: 'application/json' },
      })
      status.value = (await res.json()).available ? 'free' : 'taken'
    } catch (e) {
      if ((e as Error).name !== 'AbortError') status.value = 'error'
    }
  }, 400)

  onWatcherCleanup(() => {      // Vue 3.5+: викликається перед наступним запуском
    clearTimeout(timer)         // ще не почали - не починаємо
    controller.abort()          // уже почали - скасовуємо запит
  })
})

Як це працює: кожна зміна значення спершу «прибирає» попередній запуск - скасовує таймер і запит. Тому відповідь на застаріле значення або не надійде, або буде відкинута, і гонки не буде. До Vue 3.5 те саме робить третій аргумент колбека watch - onCleanup.

Що врахувати:

  • 400-500 мс - розумна затримка: користувач устигає дописати слово, і відповідь усе одно здається миттєвою;
  • AbortError - не помилка, його ігнорують;
  • перевірка на клієнті - підказка, а не гарантія: між перевіркою й відправкою адресу може зайняти інший користувач. Унікальність гарантує правило unique на сервері й унікальний індекс у базі;
  • перебір облікових записів: ендпойнт «чи зайнятий email» розкриває, хто зареєстрований. Обмежте частоту запитів (throttle) і подумайте, чи прийнятне це розкриття для вашого продукту;
  • у VeeValidate асинхронне правило в схемі запускається при кожній валідації поля - затримку й скасування там теж треба додати, бібліотека не робить їх сама.

Той самий прийом працює для пошуку з автодоповненням, перевірки промокоду, розрахунку вартості доставки.

Докладніше в документації: Vue: очищення побічних ефектів у watch

Схожі питання