Métodos de ciclo de vida
Utilização
Componentes e nós virtuais do DOM podem ter métodos de ciclo de vida, também conhecidos como hooks (ganchos), que são chamados em vários pontos durante o ciclo de vida de um elemento DOM.
// Exemplo de hook em componente
var ComponentWithHook = {
oninit: function (vnode) {
console.log('Inicializando componente');
},
view: function () {
return 'hello';
},
};
// Exemplo de hook em vnode
function initializeVnode() {
console.log('Inicializar vnode');
}
m(ComponentWithHook, { oninit: initializeVnode });
Todos os métodos de ciclo de vida recebem o vnode como primeiro argumento e o this
é vinculado a vnode.state
.
Os métodos de ciclo de vida são chamados apenas como um efeito colateral de uma chamada a m.render()
. Eles não são chamados se o DOM for modificado fora do Mithril.
O ciclo de vida do elemento DOM
Um elemento DOM é tipicamente criado e anexado ao documento. Ele pode então ter atributos ou nós filhos atualizados quando eventos da UI são acionados e os dados são alterados; e o elemento pode, alternativamente, ser removido do documento.
Depois que um elemento é removido, ele pode ser temporariamente retido em um pool de memória. O elemento em cache pode ser reutilizado em uma atualização subsequente (em um processo chamado reciclagem de DOM). Reciclar um elemento evita o custo de desempenho de recriar uma cópia de um elemento que existiu recentemente.
oninit
O hook oninit(vnode)
é chamado antes que um vnode seja processado pelo mecanismo do DOM virtual. É garantido que oninit
será executado antes que seu elemento DOM seja anexado ao documento e é garantido que será executado em vnodes pai antes de seus filhos, mas não fornece nenhuma garantia em relação à existência de elementos DOM ancestrais ou descendentes. Você nunca deve acessar vnode.dom
a partir do método oninit
.
Este hook não é chamado quando um elemento é atualizado, mas é chamado quando um elemento é reciclado.
Como em outros hooks, a palavra reservada this
no callback oninit
aponta para vnode.state
.
O hook oninit
é útil para inicializar o estado do componente com base em argumentos passados via vnode.attrs
ou vnode.children
.
function ComponentWithState() {
var initialData;
return {
oninit: function (vnode) {
initialData = vnode.attrs.data;
},
view: function (vnode) {
return [
// exibe os dados da inicialização:
m('div', 'Initial: ' + initialData),
// exibe os dados atuais:
m('div', 'Current: ' + vnode.attrs.data),
];
},
};
}
m(ComponentWithState, { data: 'Hello' });
Você não deve modificar os dados do model de forma síncrona a partir deste método. Como oninit
não garante o estado de outros elementos, as alterações no modelo feitas neste método podem não aparecer em toda a interface até a próxima renderização.
oncreate
O hook oncreate(vnode)
é chamado depois que um elemento DOM é criado e anexado ao documento. É garantido que oncreate
será executado no final do ciclo de renderização, portanto, é seguro ler valores de layout como vnode.dom.offsetHeight
e vnode.dom.getBoundingClientRect()
deste método.
Este hook não é chamado quando um elemento é atualizado.
Como em outros hooks, a palavra reservada this
no callback oncreate
aponta para vnode.state
. Elementos DOM cujos vnodes têm um hook oncreate
não são reciclados.
O hook oncreate
é útil para ler valores de layout que podem causar repaint, iniciar animações e inicializar bibliotecas de terceiros que precisam de uma referência ao elemento DOM.
var HeightReporter = {
oncreate: function (vnode) {
console.log('Inicializado com altura de: ', vnode.dom.offsetHeight);
},
view: function () {},
};
m(HeightReporter, { data: 'Hello' });
Você não deve modificar os dados do model de forma síncrona a partir deste método. Como oncreate
é executado no final do ciclo de renderização, as alterações do modelo criadas a partir deste método não serão refletidas na UI até o próximo ciclo de renderização.
onupdate
O hook onupdate(vnode)
é chamado depois que um elemento DOM é atualizado, enquanto anexado ao documento. É garantido que onupdate
será executado no final do ciclo de renderização, portanto, é seguro ler valores de layout como vnode.dom.offsetHeight
e vnode.dom.getBoundingClientRect()
deste método.
Este hook é chamado apenas se o elemento existia no ciclo de renderização anterior. Não é chamado quando um elemento é criado ou quando é reciclado.
Elementos DOM cujos vnodes têm um hook onupdate
não são reciclados.
O hook onupdate
é útil para ler valores de layout que podem causar repaint e para atualizar dinamicamente o estado da UI em bibliotecas de terceiros após a mudança dos dados do modelo.
function RedrawReporter() {
var count = 0;
return {
onupdate: function () {
console.log('Redesenhos até agora: ', ++count);
},
view: function () {},
};
}
m(RedrawReporter, { data: 'Hello' });
onbeforeremove
O hook onbeforeremove(vnode)
é chamado antes que um elemento DOM seja removido do documento. Se uma Promise
for retornada, o Mithril.js só remove o elemento DOM depois que a Promise
for resolvida.
Este hook é chamado somente no elemento DOM que perde seu parentNode
, mas não é executado em seus elementos filhos.
Como em outros hooks, a palavra reservada this
no callback onbeforeremove
aponta para vnode.state
. Elementos DOM cujos vnodes têm um hook onbeforeremove
não são reciclados.
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
O hook onremove(vnode)
é chamado antes que um elemento DOM seja removido do documento. Se um hook onbeforeremove
também for definido, o hook onremove
é executado após a conclusão da promise retornada de onbeforeremove
.
Este hook é chamado em qualquer elemento que é removido do documento, independentemente de ter sido desanexado diretamente de seu pai ou se é um filho de outro elemento que foi desanexado.
Como em outros hooks, a palavra reservada this
no callback onremove
aponta para vnode.state
. Elementos DOM cujos vnodes têm um hook onremove
não são reciclados.
O hook onremove
é útil para realizar tarefas de limpeza.
function Timer() {
var timeout = setTimeout(function () {
console.log('timed out');
}, 1000);
return {
onremove: function () {
clearTimeout(timeout);
},
view: function () {},
};
}
onbeforeupdate
O hook onbeforeupdate(vnode, old)
é chamado antes que um vnode seja diferenciado durante uma atualização. Se esta função for definida e retornar false
, o Mithril.js impede que a diferenciação ocorra no vnode e, consequentemente, em seus filhos.
Este hook por si só não impede que uma subárvore do DOM virtual seja gerada, a menos que a subárvore esteja encapsulada dentro de um componente.
Como em outros hooks, a palavra reservada this
no callback onbeforeupdate
aponta para vnode.state
.
Este hook é útil para reduzir a latência em atualizações quando há uma árvore DOM muito grande.
Evite otimizações prematuras
Embora Mithril.js seja flexível, alguns padrões de código são desencorajados:
Evite otimizações prematuras
Você só deve usar onbeforeupdate
para ignorar a diferenciação como último recurso. Evite usá-lo a menos que você tenha um problema de desempenho perceptível.
Normalmente, os problemas de desempenho que podem ser resolvidos com onbeforeupdate
se resumem a um array grande de itens. Neste contexto, tipicamente "grande" significa qualquer array que contenha um grande número de nós, seja em uma ampla disseminação (a infame tabela de 5000 linhas), ou em uma árvore profunda e densa.
Se você tiver um problema de desempenho, primeiro avalie se a UI oferece uma boa experiência ao usuário e, caso contrário, faça as alterações necessárias. Por exemplo, é altamente improvável que um usuário vasculhe 5000 linhas de dados brutos da tabela e é altamente provável que seja mais fácil para um usuário usar um recurso de pesquisa que retorna apenas os poucos itens mais relevantes.
Se uma solução baseada em design não for viável e você deve otimizar uma UI com um grande número de elementos DOM, aplique onbeforeupdate
no nó pai do maior array e reavalie o desempenho. Na maioria dos casos, uma única verificação deve ser suficiente. Se não for suficiente, repita o processo, mas seja cada vez mais cauteloso com cada nova declaração onbeforeupdate
. Vários onbeforeupdate
s indicam um problema no código, sugerindo falhas na priorização durante o fluxo de trabalho de design.
Evite aplicar essa otimização a outras áreas da sua aplicação "por precaução". Lembre-se de que, geralmente, mais código significa um custo de manutenção maior. Além disso, bugs relacionados a onbeforeupdate
podem ser difíceis de depurar se você depender da identidade do objeto para as verificações condicionais.
Em resumo, o hook onbeforeupdate
só deve ser usado como último recurso.