Async валидация

В библиотеке Naive UI процесс валидации форм может быть как синхронным, так и асинхронным. Асинхронная валидация особенно полезна при проверке данных на сервере, запросе уникальности логина, проверке email через API или любых других ситуациях, когда результат валидации зависит от внешнего источника.


Определение правил с асинхронными функциями

Для асинхронной валидации используется функция asyncValidator, которая может возвращать промис. Формат правила напоминает синхронные валидаторы, но с поддержкой промисов:

const rules = {
  username: [
    {
      required: true,
      message: 'Введите имя пользователя',
      trigger: 'blur'
    },
    {
      asyncValidator: async (rule, value) => {
        if (!value) return true;
        const response = await fetch(`/api/check-username?username=${value}`);
        const data = await response.json();
        if (!data.available) {
          throw new Error('Имя пользователя уже занято');
        }
        return true;
      },
      trigger: 'blur'
    }
  ]
};

Ключевые моменты:

  • asyncValidator возвращает промис или использует async/await.
  • В случае ошибки бросается исключение throw new Error('сообщение').
  • trigger определяет событие, на котором срабатывает проверка (blur, change и др.).

Интеграция с n-form

Naive UI предоставляет компонент <n-form> для организации форм и их валидации. Асинхронная проверка легко интегрируется через метод validate:

<template>
  <n-form :model="form" :rules="rules" ref="formRef">
    <n-form-item label="Имя пользователя" path="username">
      <n-input v-model:value="form.username" />
    </n-form-item>
    <n-button @click="submitForm">Отправить</n-button>
  </n-form>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const formRef = ref(null);
    const form = ref({ username: '' });

    const submitForm = async () => {
      try {
        await formRef.value.validate();
        console.log('Форма прошла валидацию');
      } catch (err) {
        console.log('Ошибка валидации:', err);
      }
    };

    return { form, rules, formRef, submitForm };
  }
};
</script>

Особенности работы с асинхронной валидацией:

  • Метод validate() возвращает промис, который выполняется только после завершения всех асинхронных проверок.
  • Ошибки валидации можно перехватывать через try/catch или обработчик catch промиса.

Асинхронные правила на уровне поля

В Naive UI можно комбинировать синхронные и асинхронные правила для одного поля. Это позволяет сначала проверить локальные ограничения (например, длину строки), а затем обращаться к серверу:

{
  asyncValidator: async (rule, value) => {
    if (value.length < 5) return true; // локальная проверка
    const res = await fetch(`/api/check?val=${value}`);
    const data = await res.json();
    if (!data.valid) throw new Error('Значение недопустимо');
    return true;
  },
  trigger: 'blur'
}

Такой подход снижает нагрузку на сервер, так как внешняя проверка запускается только после прохождения базовых условий.


Валидация нескольких полей одновременно

Асинхронная валидация хорошо сочетается с методом validateFields(fields), где можно передать массив полей для проверки. Это удобно, когда необходимо проверить только определённые элементы формы:

await formRef.value.validateFields(['username', 'email']);

Если хотя бы одно поле не прошло проверку, промис завершится ошибкой, а объект ошибки будет содержать список проблемных полей с соответствующими сообщениями.


Обработка ошибок и визуальная обратная связь

Naive UI автоматически отображает сообщения об ошибках в <n-form-item>, даже для асинхронных проверок. Сообщение формируется на основе текста, переданного через throw new Error() в asyncValidator. Важно:

  • Не использовать return false для указания ошибки — только throw new Error().
  • При необходимости динамически менять сообщение ошибки можно использовать условные конструкции внутри asyncValidator.
asyncValidator: async (rule, value) => {
  const response = await fetch(`/api/check-email?email=${value}`);
  const data = await response.json();
  if (!data.valid) {
    throw new Error(`Email ${value} уже используется`);
  }
  return true;
}

Рекомендации по производительности

  1. Дебаунс запросов: если проверка выполняется при input, использовать debounce для уменьшения количества обращений к серверу.
  2. Локальные проверки первыми: сначала проверять синхронные условия, чтобы сократить ненужные асинхронные запросы.
  3. Обработка исключений: всегда использовать try/catch для validate(), чтобы корректно обрабатывать ошибки в UI.

Асинхронная валидация в Naive UI позволяет строить гибкие и безопасные формы, объединяя локальные проверки и серверные запросы. Использование asyncValidator в сочетании с <n-form> делает процесс проверки интуитивно понятным и полностью интегрированным в реактивный цикл Vue.