Инкапсуляция состояния является одной из ключевых концепций при построении приложений на Mithril.js. Фреймворк предоставляет легковесные, но мощные инструменты для управления состоянием компонентов, позволяя отделить данные от представления и обеспечивая предсказуемое поведение интерфейса.
В Mithril.js компонент может быть представлен объектом с методами
view и oninit или функцией, возвращающей
виртуальный DOM. Основной способ инкапсуляции состояния — хранение его
внутри компонента.
const Counter = {
oninit(vnode) {
vnode.state.count = 0;
},
view(vnode) {
return m("div", [
m("p", `Счётчик: ${vnode.state.count}`),
m("button", { onclick: () => vnode.state.count++ }, "Увеличить")
]);
}
};
Ключевой момент: объект vnode.state
создаётся для каждого экземпляра компонента, что гарантирует изоляцию
состояния между разными экземплярами. Это предотвращает нежелательные
побочные эффекты при повторном использовании компонента.
Для функциональных компонентов возможна инкапсуляция состояния через
замыкания, без использования vnode.state. Такой подход
удобен для небольших модулей и уменьшает зависимость от структуры
vnode.
function Timer() {
let seconds = 0;
setInterval(() => {
seconds++;
m.redraw();
}, 1000);
return {
view() {
return m("div", `Прошло секунд: ${seconds}`);
}
};
}
Особенность: состояние внутри замыкания недоступно извне компонента, что усиливает инкапсуляцию и предотвращает прямую модификацию из других частей приложения.
Компоненты могут получать состояние извне через объект
attrs. Это позволяет разделять данные и логику, делая
компонент повторно используемым и тестируемым.
const Message = {
view(vnode) {
return m("p", vnode.attrs.text);
}
};
m.mount(document.body, {
view() {
return m(Message, { text: "Привет, Mithril!" });
}
});
Важный момент: attrs являются входными
параметрами и должны рассматриваться как неизменяемые
внутри компонента. Изменение attrs внутри компонента
нарушает предсказуемость и может привести к багам.
Для сложных приложений требуется управление общим состоянием. Mithril не накладывает строгих ограничений на глобальные объекты, однако правильная инкапсуляция достигается через модули или паттерн store, который эксплуатирует замыкания и публичные методы для доступа к данным.
const store = (() => {
let todos = [];
return {
getTodos() {
return todos;
},
addTodo(item) {
todos.push(item);
m.redraw();
}
};
})();
Компонент может использовать store без прямого доступа к
внутреннему массиву:
const TodoList = {
view() {
return m("ul", store.getTodos().map(todo => m("li", todo)));
}
};
Преимущество: глобальное состояние управляется централизованно, при этом внешние компоненты не могут напрямую изменять внутренние данные, что минимизирует ошибки и улучшает поддержку кода.
Mithril использует стратегию виртуального DOM с ручным управлением
перерисовкой через m.redraw(). Инкапсуляция состояния
требует понимания, когда и как инициировать перерисовку.
vnode.state автоматически отслеживаются при событиях DOM
(например, onclick).m.redraw(), если они происходят вне событий DOM.setTimeout(() => {
store.addTodo("Новая задача");
}, 2000);
vnode.state для
изолированного локального состояния.attrs как неизменяемый интерфейс для
передачи данных в компонент.Эти подходы позволяют строить масштабируемые и поддерживаемые приложения, где состояние компонентов строго изолировано, а взаимодействие между ними происходит через четко определённые интерфейсы.