Фреймворк Mithril строится вокруг принципа разделения ответственности, что позволяет создавать компактные, читаемые и легко поддерживаемые приложения. В основе лежит концепция компонентов, которые инкапсулируют как логику, так и представление, при этом минимизируя связность между различными частями приложения.
Компонент в Mithril — это объект с методами view и, при
необходимости, oninit, oncreate,
onupdate, onremove.
Пример базового компонента:
const Counter = {
count: 0,
view: function() {
return m("div", [
m("button", { onclick: () => this.count-- }, "-"),
m("span", this.count),
m("button", { onclick: () => this.count++ }, "+")
]);
}
};
Ключевые моменты:
view отвечает исключительно за
рендеринг и не содержит сложной логики изменения данных
вне компонента.oninit используется для инициализации
состояния компонента.Одной из ошибок при разработке на Mithril является смешение состояния приложения с визуальной логикой. Рекомендуется использовать подход, при котором компоненты получают данные через props или через глобальное состояние, а не управляют всем приложением напрямую.
Пример передачи состояния через props:
const Display = {
view: ({ attrs }) => m("p", `Счёт: ${attrs.value}`)
};
const App = {
count: 0,
view: function() {
return m("div", [
m("button", { onclick: () => this.count-- }, "-"),
m(Display, { value: this.count }),
m("button", { onclick: () => this.count++ }, "+")
]);
}
};
Такой подход обеспечивает:
Display не
зависит от внутреннего состояния App.Для сложных приложений целесообразно выделять сервисы и модули, которые отвечают за работу с данными, API или глобальным состоянием.
Пример сервиса:
const TodoService = {
todos: [],
fetchTodos: async function() {
const response = await fetch("/api/todos");
this.todos = await response.json();
},
addTodo: function(todo) {
this.todos.push(todo);
}
};
Использование сервиса в компоненте:
const TodoList = {
oninit: () => TodoService.fetchTodos(),
view: () => m("ul", TodoService.todos.map(todo => m("li", todo.text)))
};
Выделение сервисов позволяет:
Mithril предоставляет гибкий механизм передачи событий между компонентами через callback-функции, передаваемые в props.
Пример:
const Button = {
view: ({ attrs }) => m("button", { onclick: attrs.onClick }, attrs.label)
};
const Counter = {
count: 0,
view: function() {
return m("div", [
m(Button, { label: "-", onClick: () => this.count-- }),
m("span", this.count),
m(Button, { label: "+", onClick: () => this.count++ })
]);
}
};
Преимущества такого подхода:
Разделение ответственности в Mithril строится на трех уровнях:
Применение этих принципов позволяет создавать масштабируемые, легко тестируемые приложения с ясной архитектурой и минимальными побочными эффектами.