Композиция и наследование компонентов

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

Структура компонентов

В Mithril компонент — это объект с методом view, который возвращает виртуальный DOM-дерево. Компонент может быть определен как объект:

const MyComponent = {
    view: function() {
        return m("div", "Привет, Mithril!");
    }
};

или как функция:

function MyComponent() {
    return {
        view: () => m("div", "Привет, Mithril!"),
    };
}

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

Композиция компонентов

Композиция позволяет строить сложные интерфейсы из простых компонентов. Mithril делает это естественно через вызов компонентов внутри других:

const Header = {
    view: () => m("header", m("h1", "Заголовок"))
};

const Footer = {
    view: () => m("footer", "Подвал страницы")
};

const Page = {
    view: () => m("div", [
        m(Header),
        m("main", "Основной контент"),
        m(Footer)
    ])
};

Ключевые моменты композиции:

  • Компоненты могут принимать attrs — объект с атрибутами и данными.
  • Можно передавать функции и колбэки для обработки событий внутри вложенных компонентов.
  • Композиция улучшает повторное использование кода и упрощает поддержку больших приложений.

Пример передачи атрибутов:

const Button = {
    view: ({ attrs }) => m("button", { onclick: attrs.onClick }, attrs.label)
};

const App = {
    view: () => m("div", [
        m(Button, { label: "Нажми меня", onClick: () => alert("Клик!") })
    ])
};

Наследование и повторное использование логики

Хотя классическое наследование в Mithril не является обязательным, оно может применяться для организации общей логики между компонентами. Один из подходов — создание базового компонента:

function BaseComponent() {
    return {
        commonMethod: function() {
            return "Общая логика";
        },
        view: function() {
            return m("div", this.commonMethod());
        }
    };
}

function ExtendedComponent() {
    const base = BaseComponent();
    return {
        ...base,
        view: function() {
            return m("div", [
                base.commonMethod(),
                m("p", "Дополнительный контент")
            ]);
        }
    };
}

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

  • Снижение дублирования кода.
  • Централизация изменений общей логики.
  • Возможность комбинировать наследование с композицией для гибкой архитектуры.

Миксины и хуки

Для повторного использования поведения компонентов можно использовать миксины — функции, возвращающие объекты с методами или состоянием:

function TimerMixin() {
    return {
        oninit(vnode) {
            this.seconds = 0;
            this.interval = setInterval(() => {
                this.seconds++;
                m.redraw();
            }, 1000);
        },
        onremove() {
            clearInterval(this.interval);
        }
    };
}

const TimerComponent = {
    ...TimerMixin(),
    view: function() {
        return m("div", `Прошло секунд: ${this.seconds}`);
    }
};

Использование миксинов позволяет добавлять одинаковое поведение в разные компоненты без классического наследования.

Динамическая композиция

Mithril поддерживает динамическую вставку компонентов:

const components = {
    header: Header,
    footer: Footer
};

const DynamicPage = {
    view: ({ attrs }) => m("div", [
        m(components[attrs.topComponent]),
        m("main", "Контент"),
        m(components[attrs.bottomComponent])
    ])
};

// Пример вызова
m(DynamicPage, { topComponent: "header", bottomComponent: "footer" });

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

Итоговые принципы композиции и наследования

  1. Композиция компонентов — основной механизм построения интерфейсов, позволяет легко объединять и переиспользовать UI-элементы.
  2. Передача атрибутов и колбэков обеспечивает гибкость и интерактивность вложенных компонентов.
  3. Наследование и миксины помогают централизовать общую логику и повторно использовать функциональность.
  4. Динамическая вставка компонентов делает архитектуру более адаптивной и модульной.

Эффективное сочетание этих подходов позволяет строить масштабируемые и поддерживаемые приложения на Mithril с минимальной сложностью кода.