Metody životního cyklu
Použití
Komponenty a uzly virtuálního DOM mohou mít metody životního cyklu, známé také jako hooky, které jsou volány v různých bodech během životnosti DOM elementu.
// Ukázkový hook v komponentě
var ComponentWithHook = {
oninit: function (vnode) {
console.log('Inicializace komponenty');
},
view: function () {
return 'hello';
},
};
// Ukázkový hook ve vnode
function initializeVnode() {
console.log('Inicializace vnode');
}
m(ComponentWithHook, { oninit: initializeVnode });
Všechny metody životního cyklu přijímají vnode jako svůj první argument a kontext this
je nastaven na vnode.state
.
Metody životního cyklu se volají pouze při volání m.render()
. Pokud je DOM modifikován mimo Mithril, tyto metody se nespustí.
Životní cyklus DOM elementu
DOM element je typicky vytvořen a připojen k dokumentu. Poté mohou být aktualizovány jeho atributy nebo podřízené uzly, když je spuštěna událost uživatelského rozhraní a data jsou změněna; a element může být následně odstraněn z dokumentu.
Po odstranění elementu může být dočasně uložen v paměťovém poolu. Element z poolu se pak může znovu použít při další aktualizaci (tomuto procesu se říká recyklace DOMu). Recyklace elementu zabraňuje nákladům na výkon spojeným s opětovným vytvořením elementu, který existoval nedávno.
oninit
Hook oninit(vnode)
je volán předtím, než se uzel virtuálního DOM (vnode) poprvé setká s virtuálním DOM enginem. oninit
se vždy spustí před připojením DOM elementu k dokumentu. Také se zaručeně spustí na rodičovských vnode před jejich potomky. Nicméně, negarantuje existenci DOM elementů předků nebo potomků. Nikdy byste neměli přistupovat k vnode.dom
v metodě oninit
.
Tento hook není volán, když je element aktualizován, ale je volán, pokud je element recyklován.
Stejně jako u ostatních hooků, kontext this
v callbacku oninit
odkazuje na vnode.state
.
Hook oninit
je užitečný pro inicializaci stavu komponenty na základě argumentů předaných prostřednictvím vnode.attrs
nebo vnode.children
.
function ComponentWithState() {
var initialData;
return {
oninit: function (vnode) {
initialData = vnode.attrs.data;
},
view: function (vnode) {
return [
// zobrazuje data z doby inicializace:
m('div', 'Initial: ' + initialData),
// zobrazuje aktuální data:
m('div', 'Current: ' + vnode.attrs.data),
];
},
};
}
m(ComponentWithState, { data: 'Hello' });
Neměli byste synchronně modifikovat data modelu z této metody. Protože oninit
neposkytuje žádné záruky ohledně stavu ostatních elementů, změny modelu provedené v této metodě se nemusí projevit v celém uživatelském rozhraní až do dalšího cyklu vykreslování.
oncreate
Hook oncreate(vnode)
je volán poté, co je DOM element vytvořen a připojen k dokumentu. oncreate
má zaručeno, že se spustí na konci cyklu vykreslování, takže je bezpečné číst hodnoty rozložení, jako je vnode.dom.offsetHeight
a vnode.dom.getBoundingClientRect()
z této metody.
Tento hook není volán, když je element aktualizován.
Stejně jako v jiných hácích, klíčové slovo this
v callbacku oncreate
ukazuje na vnode.state
. DOM elementy, jejichž vnode mají hook oncreate
, nejsou recyklovány.
Hook oncreate
se hodí pro čtení hodnot rozvržení, které mohou vyvolat překreslení, pro spouštění animací a pro inicializaci knihoven třetích stran, které potřebují odkaz na DOM element.
var HeightReporter = {
oncreate: function (vnode) {
console.log('Inicializováno s výškou: ', vnode.dom.offsetHeight);
},
view: function () {},
};
m(HeightReporter, { data: 'Hello' });
Neměli byste synchronně modifikovat data modelu z této metody. Protože oncreate
je spuštěn na konci cyklu vykreslování, změny modelu vytvořené z této metody se neprojeví v uživatelském rozhraní až do dalšího cyklu vykreslování.
onupdate
Hook onupdate(vnode)
je volán poté, co je DOM element aktualizován, zatímco je připojen k dokumentu. onupdate
má zaručeno, že se spustí na konci cyklu vykreslování, takže je bezpečné číst hodnoty rozložení, jako je vnode.dom.offsetHeight
a vnode.dom.getBoundingClientRect()
z této metody.
Tento hook je volán pouze v případě, že element existoval v předchozím cyklu vykreslování. Není volán, když je element vytvořen nebo když je recyklován.
DOM elementy, jejichž vnode mají hook onupdate
, nejsou recyklovány.
Hook onupdate
je užitečný pro čtení hodnot rozložení, které mohou spustit překreslení, a pro dynamickou aktualizaci stavu ovlivňujícího uživatelské rozhraní v knihovnách třetích stran po změně dat modelu.
function RedrawReporter() {
var count = 0;
return {
onupdate: function () {
console.log('Překreslení dosud: ', ++count);
},
view: function () {},
};
}
m(RedrawReporter, { data: 'Hello' });
onbeforeremove
Hook onbeforeremove(vnode)
je volán těsně předtím, než je DOM element odpojen od dokumentu. Pokud je vrácen Promise, Mithril.js odpojí DOM element až po dokončení promise.
Tento hook je volán pouze na DOM elementu, který ztratí svého parentNode
, ale není volán v jeho podřízených elementech.
Stejně jako v jiných hácích, klíčové slovo this
v callbacku onbeforeremove
ukazuje na vnode.state
. DOM elementy, jejichž vnode mají hook onbeforeremove
, nejsou recyklovány.
var Fader = {
onbeforeremove: function (vnode) {
vnode.dom.classList.add('fade-out');
return new Promise(function (resolve) {
setTimeout(resolve, 1000);
});
},
view: function () {
return m('div', 'Bye');
},
};
onremove
Hook onremove(vnode)
je volán předtím, než je DOM element odstraněn z dokumentu. Pokud je definován také hook onbeforeremove
, hook onremove
se spustí po dokončení promise vráceného z onbeforeremove
.
Tento hook je volán na jakémkoli elementu, který je odstraněn z dokumentu, bez ohledu na to, zda byl přímo odpojen od svého rodiče nebo zda je podřízeným elementem jiného elementu, který byl odpojen.
Stejně jako v jiných hácích, klíčové slovo this
v callbacku onremove
ukazuje na vnode.state
. DOM elementy, jejichž vnode mají hook onremove
, nejsou recyklovány.
Hook onremove
je užitečný pro spouštění úklidových úloh.
function Timer() {
var timeout = setTimeout(function () {
console.log('vypršel čas');
}, 1000);
return {
onremove: function () {
clearTimeout(timeout);
},
view: function () {},
};
}
onbeforeupdate
Hook onbeforeupdate(vnode, old)
se volá před porovnáváním (diffingem) vnode při aktualizaci. Pokud je tato funkce definovaná a vrátí false
, Mithril.js zabrání diffingu daného vnode a tím i jeho potomků.
Tento hook sám o sobě nezabrání vygenerování podstromu virtuálního DOM, pokud podstrom není zapouzdřen v komponentě.
Stejně jako v jiných hácích, klíčové slovo this
v callbacku onbeforeupdate
ukazuje na vnode.state
.
Tento hook je užitečný pro snížení zpoždění v aktualizacích v případech, kdy existuje příliš velký strom DOM.
Vyhněte se anti-vzorům
Ačkoli je Mithril.js flexibilní, některé vzory kódu se nedoporučují:
Vyhněte se předčasným optimalizacím
onbeforeupdate
byste měli používat k přeskočení porovnávání (diffingu) pouze jako poslední možnost. Vyhněte se jeho používání, pokud nemáte znatelný problém s výkonem.
Typicky se problémy s výkonem, které lze opravit pomocí onbeforeupdate
, scvrkávají na jedno velké pole položek. V tomto kontextu "velké" obvykle znamená pole s velkým počtem uzlů, ať už se jedná o širokou strukturu (například notoricky známá tabulka s 5000 řádky) nebo hluboký, hustý strom.
Pokud máte problém s výkonem, nejprve zvažte, zda uživatelské rozhraní představuje dobrou uživatelskou zkušenost, a změňte jej, pokud tomu tak není. Například je vysoce nepravděpodobné, že by uživatel někdy probral 5000 řádků nezpracovaných dat tabulky, a je vysoce pravděpodobné, že by pro uživatele bylo snazší použít funkci vyhledávání, která vrací pouze několik nejrelevantnějších položek.
Pokud není řešení založené na návrhu proveditelné a musíte optimalizovat uživatelské rozhraní s velkým počtem DOM elementů, použijte onbeforeupdate
na rodičovský uzel největšího pole a znovu vyhodnoťte výkon. V naprosté většině případů stačí jedna kontrola. Ve vzácných případech, kdy tomu tak není, opakujte postup, ale měli byste být stále opatrnější ohledně každé nové deklarace onbeforeupdate
. Použití více onbeforeupdate
naznačuje, že v návrhu existují problémy s prioritizací.
Vyhněte se optimalizaci dalších částí aplikace "jen pro jistotu". Pamatujte, že obecně řečeno, více kódu znamená vyšší náklady na údržbu než méně kódu a chyby související s onbeforeupdate
mohou být obzvláště obtížné řešit, pokud se spoléháte na identitu objektu pro jeho podmíněné kontroly.
Opět, hook onbeforeupdate
by měl být používán pouze jako poslední možnost.