Mithril.js — это современный легковесный JavaScript-фреймворк для создания одностраничных приложений. Основой работы с Mithril является понимание того, как контекст выполнения и область видимости взаимодействуют с компонентами, виртуальным DOM и асинхронными операциями.
Компонент в Mithril — это объект с методами view и
необязательными жизненными циклами (oninit,
oncreate, onupdate, onremove,
onbeforeremove). Контекст выполнения этих методов
определяется тем, как Mithril вызывает функции.
oninit выполняется один раз при
инициализации компонента. Внутри него this ссылается на
компонент, а любые свойства можно сохранять прямо на this
для использования в других методах.const Counter = {
oninit(vnode) {
this.count = 0;
},
view(vnode) {
return m("button", { onclick: () => this.count++ }, `Count: ${this.count}`);
}
};
oncreate,
onupdate) также получают доступ к vnode,
который содержит как attrs компонента, так и
state, где можно хранить данные между рендерами. В отличие
от this, использование vnode.state безопаснее
при функциональных компонентах.Область видимости в Mithril тесно связана с JavaScript-замыканиями и областью видимости переменных.
let, const или
var внутри компонента, доступны только внутри этой функции.
При повторных рендерах их значения теряются, если не использовать
vnode.state.const Timer = {
oninit(vnode) {
vnode.state.seconds = 0;
setInterval(() => vnode.state.seconds++, 1000);
},
view(vnode) {
return m("div", `Seconds: ${vnode.state.seconds}`);
}
};
Глобальная область — переменные, объявленные вне компонентов, доступны во всех компонентах. Это удобно для глобального состояния, но нежелательно для инкапсуляции.
Props (attrs) — параметры,
переданные компоненту, находятся в vnode.attrs и доступны в
любой точке компонента через этот объект. Они остаются неизменными, если
не использовать их вместе с внутренним состоянием компонента.
const Greeting = {
view(vnode) {
return m("h1", `Hello, ${vnode.attrs.name}`);
}
};
m.mount(document.body, { view: () => m(Greeting, { name: "Mithril" }) });
Асинхронные функции, такие как таймеры или fetch-запросы, часто
создают замыкания, которые захватывают локальные переменные и
vnode.state. Это важно для корректного обновления
интерфейса при изменении данных:
const DataLoader = {
oninit(vnode) {
vnode.state.data = null;
fetch("/api/data")
.then(res => res.json())
.then(json => {
vnode.state.data = json;
m.redraw(); // обязательный вызов для обновления view
});
},
view(vnode) {
return m("div", vnode.state.data ? JSON.stringify(vnode.state.data) : "Loading...");
}
};
Если попытаться использовать обычные локальные переменные без
сохранения их в vnode.state, данные потеряются при
следующем рендере.
Mithril поддерживает как объектные компоненты с методами жизненного
цикла, так и функциональные компоненты. В функциональных компонентах нет
this, поэтому всё состояние нужно хранить в замыканиях или
через vnode.state:
const FunctionalCounter = () => {
let count = 0;
return {
view: () => m("button", { onclick: () => { count++; m.redraw(); } }, `Count: ${count}`)
};
};
Использование vnode.state делает функциональные
компоненты более безопасными для повторного рендера и асинхронных
операций.
vnode.state.view можно использовать для
временных вычислений, но не для сохранения состояния.vnode.state, чтобы изменения корректно отражались в
интерфейсе.Контекст выполнения и область видимости в Mithril напрямую влияют на
стабильность и предсказуемость поведения компонентов. Правильное
использование vnode.state и замыканий обеспечивает
безопасное управление состоянием, корректное обновление интерфейса и
упрощает сопровождение кода в больших приложениях.