Métodos de ciclo de vida
Uso
Los Componentes y los nodos del DOM Virtual pueden tener métodos de ciclo de vida, también conocidos como hooks, que se invocan en diferentes momentos durante el ciclo de vida de un elemento DOM.
// Hook de ejemplo en un componente
var ComponentWithHook = {
oninit: function (vnode) {
console.log('inicializando el componente');
},
view: function () {
return 'hello';
},
};
// Hook de ejemplo en un vnode
function initializeVnode() {
console.log('inicializando el vnode');
}
m(ComponentWithHook, { oninit: initializeVnode });
Todos los métodos del ciclo de vida reciben el vnode como primer argumento, y la palabra clave this
está enlazada a vnode.state
.
Los métodos de ciclo de vida solo se invocan como efecto secundario de una llamada a m.render()
. No se invocan si el DOM se modifica fuera de Mithril.
El ciclo de vida del elemento DOM
Normalmente, un elemento DOM se crea y se añade al documento. A continuación, sus atributos o nodos hijo pueden actualizarse cuando se activa un evento de la interfaz de usuario y se modifican los datos; finalmente, el elemento puede eliminarse del documento.
Una vez que se elimina un elemento, puede que se conserve temporalmente en un pool de memoria. Este elemento almacenado en el pool puede reutilizarse en una actualización posterior (en un proceso llamado reciclaje del DOM). El reciclaje de un elemento evita incurrir en el coste de rendimiento de recrear una copia de un elemento que existió recientemente.
oninit
El hook oninit(vnode)
se invoca antes de que el motor del DOM virtual procese un vnode. Se garantiza que oninit
se ejecuta antes de que el elemento DOM se añada al documento, y se garantiza que se ejecuta en los vnodes padre antes que en sus hijos, pero no ofrece ninguna garantía con respecto a la existencia de elementos DOM ancestros o descendientes. No debes acceder a vnode.dom
desde el método oninit
.
Este hook no se invoca cuando se actualiza un elemento, pero sí se invoca si se recicla un elemento.
Al igual que en otros hooks, la palabra clave this
en la función callback oninit
apunta a vnode.state
.
El hook oninit
es útil para inicializar el estado del componente basándose en los argumentos pasados mediante vnode.attrs
o vnode.children
.
function ComponentWithState() {
var initialData;
return {
oninit: function (vnode) {
initialData = vnode.attrs.data;
},
view: function (vnode) {
return [
// muestra los datos iniciales:
m('div', 'Initial: ' + initialData),
// muestra los datos actuales:
m('div', 'Current: ' + vnode.attrs.data),
];
},
};
}
m(ComponentWithState, { data: 'Hello' });
No se deben modificar los datos del estado de forma síncrona desde este método. Puesto que oninit
no ofrece ninguna garantía con respecto al estado de otros elementos, los cambios en el modelo creados desde este método podrían no reflejarse en todas las partes de la interfaz de usuario hasta el siguiente ciclo de renderizado.
oncreate
El hook oncreate(vnode)
se invoca después de que se crea un elemento DOM y se añade al documento. Se garantiza que oncreate
se ejecuta al final del ciclo de renderizado, por lo que es seguro leer valores de disposición, como vnode.dom.offsetHeight
y vnode.dom.getBoundingClientRect()
, desde este método.
Este hook no se invoca cuando se actualiza un elemento.
Al igual que en otros hooks, la palabra clave this
en la función callback oncreate
apunta a vnode.state
. Los elementos DOM cuyos vnodes tienen un hook oncreate
no se reciclan.
El hook oncreate
es útil para leer valores de diseño que pueden desencadenar un repintado, iniciar animaciones e inicializar bibliotecas de terceros que requieren una referencia al elemento DOM.
var HeightReporter = {
oncreate: function (vnode) {
console.log('Inicializado con una altura de: ', vnode.dom.offsetHeight);
},
view: function () {},
};
m(HeightReporter, { data: 'Hello' });
No se deben modificar los datos del estado de forma síncrona desde este método. Puesto que oncreate
se ejecuta al final del ciclo de renderizado, los cambios en el modelo creados desde este método no se reflejarán en la interfaz de usuario hasta el siguiente ciclo de renderizado.
onupdate
El hook onupdate(vnode)
se invoca después de que se actualiza un elemento DOM, mientras está añadido al documento. Se garantiza que onupdate
se ejecuta al final del ciclo de renderizado, por lo que es seguro leer valores de disposición, como vnode.dom.offsetHeight
y vnode.dom.getBoundingClientRect()
, desde este método.
Este hook solo se invoca si el elemento existía en el ciclo de renderizado anterior. No se invoca cuando se crea un elemento o cuando se recicla.
Los elementos DOM cuyos vnodes tienen un hook onupdate
no se reciclan.
El hook onupdate
es útil para leer valores de diseño que pueden desencadenar un repintado, y para actualizar dinámicamente el estado que afecta a la interfaz de usuario en bibliotecas de terceros después de que se modifiquen los datos del modelo.
function RedrawReporter() {
var count = 0;
return {
onupdate: function () {
console.log('Redibujados hasta ahora: ', ++count);
},
view: function () {},
};
}
m(RedrawReporter, { data: 'Hello' });
onbeforeremove
El hook onbeforeremove(vnode)
se invoca antes de que se separe un elemento DOM del documento. Si se devuelve una Promesa, Mithril.js solo separa el elemento DOM después de que se resuelva la promesa.
Este hook solo se invoca en el elemento DOM que pierde su parentNode
, pero no se invoca en sus elementos hijo.
Al igual que en otros hooks, la palabra clave this
en la función callback onbeforeremove
apunta a vnode.state
. Los elementos DOM cuyos vnodes tienen un hook onbeforeremove
no se reciclan.
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
El hook onremove(vnode)
se invoca antes de que se elimine un elemento DOM del documento. Si también se define un hook onbeforeremove
, el hook onremove
se ejecuta después de que se resuelva la promesa que devuelve onbeforeremove
.
Este hook se invoca en cualquier elemento que se elimine del documento, independientemente de si se separó directamente de su padre o si es un hijo de otro elemento que se separó.
Al igual que en otros hooks, la palabra clave this
en la función callback onremove
apunta a vnode.state
. Los elementos DOM cuyos vnodes tienen un hook onremove
no se reciclan.
El hook onremove
es útil para ejecutar tareas de limpieza.
function Timer() {
var timeout = setTimeout(function () {
console.log('se agotó el tiempo');
}, 1000);
return {
onremove: function () {
clearTimeout(timeout);
},
view: function () {},
};
}
onbeforeupdate
El hook onbeforeupdate(vnode, old)
se invoca antes de que se analicen las diferencias en un vnode en una actualización. Si esta función está definida y devuelve false, Mithril.js evita que se realice una comparación en el vnode y, en consecuencia, en los hijos del vnode.
Este hook por sí solo no evita que se genere un subárbol del DOM virtual a menos que el subárbol esté encapsulado dentro de un componente.
Al igual que en otros hooks, la palabra clave this
en la función callback onbeforeupdate
apunta a vnode.state
.
Este hook es útil para reducir la latencia en las actualizaciones en los casos en los que hay un árbol DOM que sea demasiado grande.
Evitar antipatrones
Aunque Mithril.js es flexible, se desaconsejan algunos patrones de código:
Evitar optimizaciones prematuras
Solo debes usar onbeforeupdate
para omitir la comparación como último recurso. Evita usarlo a menos que tengas un problema de rendimiento notable.
Normalmente, los problemas de rendimiento que se pueden solucionar mediante onbeforeupdate
se reducen a una gran lista de elementos. En este contexto, normalmente "grande" significa cualquier matriz que contenga un gran número de nodos, ya sea en una amplia extensión (la conocida tabla de 5000 filas) o en un árbol profundo y denso.
Si tiene un problema de rendimiento, primero considere si la interfaz de usuario ofrece una buena experiencia de usuario y cámbiela si no es así. Por ejemplo, es muy poco probable que un usuario examine 5000 filas de datos de tabla sin procesar, y es muy probable que sea más fácil para un usuario utilizar una función de búsqueda que devuelva solo los elementos más relevantes.
Si una solución basada en el diseño no es factible, y debe optimizar una interfaz de usuario con un gran número de elementos DOM, aplique onbeforeupdate
en el nodo padre de la matriz más grande y vuelva a evaluar el rendimiento. En la gran mayoría de los casos, una sola comprobación debería ser suficiente. En el raro caso de que no lo sea, repita el proceso, pero debes tener cada vez más cuidado con cada nueva declaración de onbeforeupdate
. Múltiples onbeforeupdate
son un indicio de que hay problemas de priorización en el flujo de trabajo de diseño.
Evite aplicar la optimización a otras áreas de su aplicación "por si acaso". Recuerde que, en general, más código implica un mayor coste de mantenimiento que menos código, y los errores relacionados con onbeforeupdate
pueden ser especialmente difíciles de detectar si se confía en la identidad del objeto para sus comprobaciones condicionales.
De nuevo, el hook onbeforeupdate
solo debe usarse como último recurso.