Metody cyklu życia
Użycie
Komponenty i węzły virtualnego DOM mogą definiować metody cyklu życia, zwane również hookami, które są wywoływane w określonych momentach istnienia elementu DOM.
// Przykładowy hook w komponencie
var ComponentWithHook = {
oninit: function (vnode) {
console.log('initialize component');
},
view: function () {
return 'hello';
},
};
// Przykładowy hook w vnode
function initializeVnode() {
console.log('initialize vnode');
}
m(ComponentWithHook, { oninit: initializeVnode });
Wszystkie metody cyklu życia otrzymują węzeł vnode jako pierwszy argument, a słowo kluczowe this
jest powiązane z vnode.state
.
Metody cyklu życia są wywoływane wyłącznie jako efekt uboczny wywołania m.render()
. Nie są wywoływane, jeśli DOM jest modyfikowany poza kontrolą Mithril.
Cykl życia elementu DOM
Element DOM jest zazwyczaj tworzony i dołączany do dokumentu. Następnie jego atrybuty lub węzły potomne mogą być aktualizowane w odpowiedzi na zdarzenia UI i zmiany danych. Element może być również usunięty z dokumentu.
Po usunięciu element może być tymczasowo przechowywany w puli pamięci. Element z puli może być ponownie użyty w kolejnej aktualizacji (proces ten nazywany jest recyklingiem DOM). Recykling elementu pozwala uniknąć kosztownych operacji ponownego tworzenia elementu, który niedawno istniał.
oninit
Hook oninit(vnode)
jest wywoływany, zanim węzeł vnode zostanie przetworzony przez silnik virtualnego DOM. oninit
gwarantuje uruchomienie przed dołączeniem elementu DOM do dokumentu i gwarantuje uruchomienie na węzłach vnode rodziców przed ich dziećmi. Nie oferuje jednak żadnych gwarancji dotyczących istnienia elementów DOM przodków lub potomków. Nie należy uzyskiwać dostępu do vnode.dom
z metody oninit
.
Ten hook nie jest wywoływany podczas aktualizacji elementu, ale jest wywoływany, jeśli element jest recyklingowany.
Podobnie jak w innych hookach, słowo kluczowe this
w callbacku oninit
wskazuje na vnode.state
.
Hook oninit
jest przydatny do inicjalizacji stanu komponentu na podstawie argumentów przekazywanych w vnode.attrs
lub vnode.children
.
function ComponentWithState() {
var initialData;
return {
oninit: function (vnode) {
initialData = vnode.attrs.data;
},
view: function (vnode) {
return [
// wyświetla dane z momentu inicjalizacji:
m('div', 'Initial: ' + initialData),
// wyświetla aktualne dane:
m('div', 'Current: ' + vnode.attrs.data),
];
},
};
}
m(ComponentWithState, { data: 'Hello' });
Nie należy modyfikować danych modelu synchronicznie w tej metodzie. Ponieważ oninit
nie daje żadnych gwarancji dotyczących stanu innych elementów, zmiany modelu wprowadzone w tej metodzie mogą nie być odzwierciedlone we wszystkich częściach interfejsu użytkownika aż do następnego cyklu renderowania.
oncreate
Hook oncreate(vnode)
jest wywoływany po utworzeniu elementu DOM i dołączeniu go do dokumentu. oncreate
gwarantuje uruchomienie na końcu cyklu renderowania, więc można bezpiecznie odczytywać wartości układu, takie jak vnode.dom.offsetHeight
i vnode.dom.getBoundingClientRect()
z tej metody.
Ten hook nie jest wywoływany podczas aktualizacji elementu.
Podobnie jak w innych hookach, słowo kluczowe this
w callbacku oncreate
wskazuje na vnode.state
. Elementy DOM, których węzły vnode mają hook oncreate
, nie są poddawane recyklingowi.
Hook oncreate
jest przydatny do odczytywania wartości układu, które mogą wywołać ponowne przerysowanie, uruchamiania animacji i inicjalizacji bibliotek zewnętrznych, które wymagają odniesienia do elementu DOM.
var HeightReporter = {
oncreate: function (vnode) {
console.log('Initialized with height of: ', vnode.dom.offsetHeight);
},
view: function () {},
};
m(HeightReporter, { data: 'Hello' });
Nie należy modyfikować danych modelu synchronicznie z tej metody. Ponieważ oncreate
jest uruchamiany na końcu cyklu renderowania, zmiany modelu wprowadzone w tej metodzie nie zostaną odzwierciedlone w interfejsie użytkownika aż do następnego cyklu renderowania.
onupdate
Hook onupdate(vnode)
jest wywoływany po zaktualizowaniu elementu DOM, gdy jest on dołączony do dokumentu. onupdate
gwarantuje uruchomienie na końcu cyklu renderowania, więc można bezpiecznie odczytywać wartości układu, takie jak vnode.dom.offsetHeight
i vnode.dom.getBoundingClientRect()
z tej metody.
Ten hook jest wywoływany tylko wtedy, gdy element istniał w poprzednim cyklu renderowania. Nie jest wywoływany, gdy element jest tworzony lub gdy jest poddawany recyklingowi.
Elementy DOM, których węzły vnode mają hook onupdate
, nie są poddawane recyklingowi.
Hook onupdate
jest przydatny do odczytywania wartości układu, które mogą wywołać ponowne przerysowanie, oraz do dynamicznej aktualizacji stanu wpływającego na interfejs użytkownika w bibliotekach zewnętrznych po zmianie danych modelu.
function RedrawReporter() {
var count = 0;
return {
onupdate: function () {
console.log('Redraws so far: ', ++count);
},
view: function () {},
};
}
m(RedrawReporter, { data: 'Hello' });
onbeforeremove
Hook onbeforeremove(vnode)
jest wywoływany przed odłączeniem elementu DOM od dokumentu. Jeśli zostanie zwrócona Promise, Mithril.js odłączy element DOM dopiero po jej zakończeniu.
Ten hook jest wywoływany tylko na elemencie DOM, który traci swój parentNode
, ale nie jest wywoływany na jego elementach potomnych.
Podobnie jak w innych hookach, słowo kluczowe this
w callbacku onbeforeremove
wskazuje na vnode.state
. Elementy DOM, których węzły vnode mają hook onbeforeremove
, nie są poddawane recyklingowi.
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)
jest wywoływany przed usunięciem elementu DOM z dokumentu. Jeśli zdefiniowany jest również hook onbeforeremove
, hook onremove
jest uruchamiany po zakończeniu Promise zwróconej z onbeforeremove
.
Ten hook jest wywoływany na każdym elemencie, który jest usuwany z dokumentu, niezależnie od tego, czy został bezpośrednio odłączony od rodzica, czy też jest elementem potomnym innego elementu, który został odłączony.
Podobnie jak w innych hookach, słowo kluczowe this
w callbacku onremove
wskazuje na vnode.state
. Elementy DOM, których węzły vnode mają hook onremove
, nie są poddawane recyklingowi.
Hook onremove
jest przydatny do wykonywania zadań porządkowych.
function Timer() {
var timeout = setTimeout(function () {
console.log('timed out');
}, 1000);
return {
onremove: function () {
clearTimeout(timeout);
},
view: function () {},
};
}
onbeforeupdate
Hook onbeforeupdate(vnode, old)
jest wywoływany przed porównaniem (ang. diff) węzła vnode podczas aktualizacji. Jeśli ta funkcja jest zdefiniowana i zwraca false
, Mithril.js zapobiega porównywaniu węzła vnode, a tym samym jego węzłów potomnych.
Sam ten hook nie zapobiega generowaniu poddrzewa virtualnego DOM, chyba że poddrzewo jest zamknięte w komponencie.
Podobnie jak w innych hookach, słowo kluczowe this
w callbacku onbeforeupdate
wskazuje na vnode.state
.
Ten hook jest przydatny do zmniejszenia opóźnień w aktualizacjach w sytuacjach, gdy istnieje bardzo duże drzewo DOM.
Unikanie antywzorców
Chociaż Mithril.js jest elastyczny, niektóre wzorce kodowania są odradzane:
Unikanie przedwczesnych optymalizacji
Należy używać onbeforeupdate
do pomijania porównywania tylko w ostateczności. Unikaj używania go, chyba że występuje zauważalny problem z wydajnością.
Zazwyczaj problemy z wydajnością, które można rozwiązać za pomocą onbeforeupdate
, są związane z jedną dużą tablicą elementów. W tym kontekście "duża" zazwyczaj oznacza tablicę, która zawiera dużą liczbę węzłów, zarówno w szerokim rozproszeniu (osławiona tabela z 5000 wierszy), jak i w głębokim, gęstym drzewie.
Jeśli występuje problem z wydajnością, najpierw zastanów się, czy interfejs użytkownika zapewnia dobre wrażenia użytkownika i zmień go, jeśli nie. Na przykład, jest mało prawdopodobne, aby użytkownik kiedykolwiek przeglądał 5000 wierszy surowych danych tabeli, i jest bardzo prawdopodobne, że łatwiej byłoby użytkownikowi użyć funkcji wyszukiwania, która zwraca tylko kilka najbardziej odpowiednich elementów.
Jeśli rozwiązanie oparte na projekcie nie jest wykonalne i konieczne jest zoptymalizowanie interfejsu użytkownika z dużą liczbą elementów DOM, zastosuj onbeforeupdate
na węźle nadrzędnym największej tablicy i ponownie oceń wydajność. W zdecydowanej większości przypadków pojedyncza kontrola powinna być wystarczająca. W rzadkich przypadkach, gdy tak nie jest, powtórz proces, ale należy zachować ostrożność w odniesieniu do każdej nowej deklaracji onbeforeupdate
. Wiele onbeforeupdate
to sygnał, że w procesie projektowania występują problemy z ustalaniem priorytetów.
Unikaj stosowania optymalizacji do innych obszarów aplikacji prewencyjnie. Pamiętaj, że ogólnie rzecz biorąc, więcej kodu wiąże się z wyższymi kosztami utrzymania niż mniej kodu, a błędy związane z onbeforeupdate
mogą być szczególnie trudne do rozwiązania, jeśli polegasz na identyczności obiektów w swoich kontrolach warunkowych.
Jeszcze raz, hook onbeforeupdate
powinien być używany tylko w ostateczności.