Проверка событий

Atomico предоставляет современный подход к работе с веб-компонентами на базе JavaScript, интегрируя реактивность и управление состоянием. Важной частью взаимодействия компонентов является обработка событий. События позволяют компонентам информировать внешнюю среду о внутренних изменениях или реагировать на действия пользователя.

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

В Atomico события реализуются через механизм emit, встроенный в каждый компонент. Метод emit используется для генерации пользовательских событий, которые могут быть пойманы родительскими элементами или другими компонентами.

import { component, html, useEvent } from "atomico";

function MyButton() {
    const clickEvent = useEvent("button-click");

    return html`
        <button oncl ick=${() => clickEvent.emit({ count: 1 })}>
            Нажми меня
        </button>
    `;
}

customElements.define("my-button", component(MyButton));

В этом примере создается пользовательское событие button-click, которое отправляет объект с данными при нажатии на кнопку. Метод useEvent возвращает объект с методом emit, позволяющий сгенерировать событие.

Подписка на события

Компоненты, которые используют события, могут быть подключены через атрибуты, либо через стандартные методы DOM. В Atomico подписка часто осуществляется через JSX-подобные события:

function App() {
    return html`
        <my-button onbutton-click=${(e) => console.log(e.detail)}>
        </my-button>
    `;
}

Здесь e.detail содержит данные, переданные через emit. Такой подход обеспечивает прямое связывание события и обработчика, упрощая передачу данных между компонентами.

Проверка и тестирование событий

Для корректной работы компонентов важно проверять, что события вызываются и передают правильные данные. В Atomico проверка событий может выполняться через стандартные средства тестирования DOM, например, используя Jest или Testing Library:

import { render, fireEvent } from "@testing-library/atomico";
import MyButton from "./MyButton";

test("button emits click event", async () => {
    const { getByText } = render(html`<my-button></my-button>`);
    const button = getByText("Нажми меня");

    const listener = jest.fn();
    button.addEventListener("button-click", listener);

    await fireEvent.click(button);

    expect(listener).toHaveBeenCalledTimes(1);
    expect(listener.mock.calls[0][0].detail).toEqual({ count: 1 });
});

Ключевое здесь — использование fireEvent для симуляции действий пользователя и проверка через mock-функции, что событие вызвано и содержит правильные данные.

События с асинхронными действиями

Atomico поддерживает события, инициируемые в асинхронных процессах, таких как загрузка данных или таймеры. Важно учитывать, что обработка событий может происходить с задержкой, и необходимо корректно передавать состояние.

function AsyncButton() {
    const loadEvent = useEvent("data-loaded");

    const fetchData = async () => {
        const response = await fetch("/api/data");
        const data = await response.json();
        loadEvent.emit({ data });
    };

    return html`
        <button oncl ick=${fetchData}>Загрузить данные</button>
    `;
}

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

Применение фильтров и условий при генерации событий

Для предотвращения лишних уведомлений часто применяются условия при вызове emit. Можно проверять состояние компонента или фильтровать данные перед отправкой:

function ConditionalButton({ enabled }) {
    const conditionalEvent = useEvent("conditional-click");

    return html`
        <button oncl ick=${() => enabled && conditionalEvent.emit({ enabled })}>
            Нажми если можно
        </button>
    `;
}

Только при истинном значении свойства enabled событие будет отправлено, что позволяет контролировать поток информации между компонентами.

Совместное использование с Shadow DOM

Atomico по умолчанию использует Shadow DOM, поэтому события, сгенерированные внутри компонента, могут всплывать наружу. Метод emit автоматически делает событие bubbling, что позволяет ловить его на уровне родителя без дополнительных настроек:

<my-button onbutton-click=${handleClick}></my-button>

Такое поведение упрощает организацию сложных интерфейсов, где события от вложенных компонентов собираются и обрабатываются на более высоком уровне.

Стандартизация событий

Рекомендуется придерживаться единых правил именования событий: kebab-case для пользовательских событий и четкая структура detail для передаваемых данных. Это облегчает поддержку кода и интеграцию компонентов в большие проекты.


Понимание и правильное использование событий в Atomico позволяет строить гибкие, реактивные интерфейсы, где компоненты взаимодействуют через строго определенные каналы связи, обеспечивая надежность и предсказуемость поведения приложения.