Передача данных между компонентами

Mithril — минималистичный фреймворк для создания одностраничных приложений, где компоненты играют ключевую роль в организации интерфейса. Передача данных между компонентами реализуется через свойства (attrs), контекст или внешние хранилища состояния. Рассмотрим эти подходы подробно.


Использование атрибутов (attrs)

Каждый компонент в Mithril может принимать атрибуты, передаваемые при его вызове. Атрибуты доступны через объект vnode.attrs. Этот подход аналогичен props в React и является основным способом передачи данных от родительского компонента к дочернему.

const Child = {
    view: (vnode) => {
        return m("div", `Привет, ${vnode.attrs.name}!`);
    }
};

const Parent = {
    view: () => {
        return m(Child, { name: "Мир" });
    }
};

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

  • Атрибуты доступны только для чтения внутри компонента. Изменение их напрямую не рекомендуется.
  • Можно передавать любые типы данных: строки, числа, функции, объекты.

Передача функций для обратного вызова

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

const Child = {
    view: (vnode) => {
        return m("button", { onclick: () => vnode.attrs.onClick("данные") }, "Отправить данные");
    }
};

const Parent = {
    onChildClick: (data) => {
        console.log("Получены данные:", data);
    },
    view: () => {
        return m(Child, { onClick: Parent.onChildClick });
    }
};

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

  • Используется для передачи событий и управления состоянием родителя.
  • Позволяет поддерживать односторонний поток данных.

Работа с глобальным состоянием

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

const store = {
    count: 0,
    increment() {
        this.count++;
    }
};

const Counter = {
    view: () => {
        return m("div", [
            m("p", `Счётчик: ${store.count}`),
            m("button", { onclick: () => store.increment() }, "Увеличить")
        ]);
    }
};

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

  • Все компоненты, использующие store, автоматически получают актуальные данные при перерисовке.
  • Можно сочетать с m.redraw() для явного обновления интерфейса.

Вложенные компоненты и композиция

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

const Item = {
    view: (vnode) => m("li", vnode.attrs.text)
};

const List = {
    view: (vnode) => m("ul", vnode.attrs.items.map(item => m(Item, { text: item })))
};

const App = {
    view: () => m(List, { items: ["Пункт 1", "Пункт 2", "Пункт 3"] })
};

Рекомендации:

  • Избегать передачи слишком большого количества данных через attrs.
  • Стараться использовать глобальное состояние или контекст для повторно используемых данных.

Контекст компонента

Mithril поддерживает контекстные данные, которые передаются через vnode.state. Это позволяет хранить локальное состояние компонента, недоступное напрямую родителю.

const Toggle = {
    oninit: (vnode) => {
        vnode.state.active = false;
    },
    view: (vnode) => {
        return m("button", {
            onclick: () => vnode.state.active = !vnode.state.active
        }, vnode.state.active ? "Вкл" : "Выкл");
    }
};

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

  • Данные в vnode.state живут только в рамках компонента.
  • Идеально для управления локальным состоянием без загрязнения глобального пространства.

Рекомендации по архитектуре передачи данных

  1. Односторонний поток данных — родитель → дочерний через attrs; дочерний → родитель через функции обратного вызова.
  2. Локальное состояние использовать для независимых компонентов (vnode.state).
  3. Глобальное состояние применять для общих данных, используемых в разных частях приложения.
  4. Избегать глубоких цепочек attrs, если данные должны проходить через несколько уровней — лучше использовать store или контекст.

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