Валидация входных данных

Atomico — это библиотека для создания веб-компонентов на JavaScript с реактивной моделью состояния и удобным управлением жизненным циклом компонентов. Одним из ключевых аспектов разработки компонентов является валидная обработка входных данных, поступающих через свойства (props) и события.


Свойства компонентов и их типизация

В Atomico свойства компонента описываются через функцию props:

import { c, useProp } from "atomico";

function MyComponent({ name }) {
    return <div>{name}</div>;
}

MyComponent.props = {
    name: String
};

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

  • Типы данных: Atomico поддерживает стандартные конструкторы JavaScript (String, Number, Boolean, Array, Object) для определения типа свойства. Если значение не соответствует указанному типу, библиотека автоматически приводит его к нужному типу, если это возможно, либо игнорирует некорректное значение.
  • Значения по умолчанию задаются через value:
MyComponent.props = {
    name: {
        type: String,
        value: "Без имени"
    }
};
  • Обязательные свойства. В Atomico отсутствует нативная проверка обязательности свойства, но можно реализовать её через хук useProp:
function MyComponent({ name }) {
    const safeName = useProp("name", name || "Аноним");
    return <div>{safeName}</div>;
}

Валидация сложных структур данных

Для объектов и массивов одного типа необходимо использовать кастомную валидацию через функцию validate в описании свойства:

MyComponent.props = {
    users: {
        type: Array,
        value: [],
        validate: (value) => value.every(user => user.name && typeof user.name === "string")
    }
};

Особенности:

  • Функция validate должна возвращать true, если значение корректно, и false, если нет.
  • При неправильных данных значение свойства остаётся прежним или берётся значение по умолчанию.

Реактивная проверка и трансформация данных

Atomico позволяет не только проверять, но и трансформировать данные перед применением:

MyComponent.props = {
    age: {
        type: Number,
        value: 0,
        validate: (value) => value >= 0,
        transform: (value) => Math.max(0, value)
    }
};
  • validate отвечает за корректность.
  • transform позволяет изменить значение до применения, что особенно удобно для числовых и строковых данных с ограничениями.

Валидация через события

Компоненты Atomico могут проверять данные, поступающие через события:

function MyComponent() {
    const handleInput = (event) => {
        const value = event.target.value;
        if (!/^\d+$/.test(value)) {
            event.preventDefault();
        }
    };

    return <input onIn put={handleInput} />;
}

Особенности подхода:

  • Можно комбинировать нативную проверку DOM и свойства validate.
  • Позволяет реализовать мгновенную фильтрацию данных до изменения состояния компонента.

Интеграция с формами и внешними библиотеками

Atomico совместим с любыми библиотечными решениями для валидации, например, yup или zod:

import * as yup from "yup";

const schema = yup.object({
    name: yup.string().required(),
    age: yup.number().positive().integer()
});

function MyComponent({ name, age }) {
    try {
        schema.validateSync({ name, age });
        return <div>{name} — {age}</div>;
    } catch {
        return <div>Некорректные данные</div>;
    }
}

Преимущества такого подхода:

  • Комплексная проверка сразу нескольких свойств.
  • Возможность интеграции с формами и серверной логикой.
  • Удобная обработка ошибок и сообщений пользователю.

Советы по безопасной валидации

  1. Всегда задавать значения по умолчанию для всех свойств, особенно для объектов и массивов.
  2. Использовать validate для массивов и объектов, так как простая проверка типа недостаточна.
  3. Объединять проверку типов и трансформацию данных, чтобы состояние компонента всегда оставалось корректным.
  4. Валидация через события эффективна для интерактивных элементов, таких как формы и поля ввода.
  5. Интеграция с внешними схемами полезна для сложных приложений с множеством зависимостей данных.

Практика реактивной валидации

Использование useProp и validate вместе обеспечивает безопасную реактивность, где изменения данных автоматически проходят проверку и трансформацию:

function MyComponent({ score }) {
    const safeScore = useProp("score", 0);
    
    return <div>Очки: {Math.max(0, safeScore)}</div>;
}

MyComponent.props = {
    score: {
        type: Number,
        value: 0,
        validate: (v) => v >= 0
    }
};

Такой подход минимизирует риск некорректных данных в состоянии компонента и упрощает отладку приложений на Atomico.