Méthodes de cycle de vie
Utilisation
Les composants et les nœuds du DOM virtuel peuvent avoir des méthodes de cycle de vie, aussi appelées hooks, qui sont invoquées à différents moments pendant la durée de vie d'un élément DOM.
// Exemple de hook dans un composant
var ComponentWithHook = {
oninit: function (vnode) {
console.log('initialisation du composant');
},
view: function () {
return 'hello';
},
};
// Exemple de hook dans un vnode
function initializeVnode() {
console.log('initialisation du vnode');
}
m(ComponentWithHook, { oninit: initializeVnode });
Toutes les méthodes de cycle de vie reçoivent le vnode comme premier argument, et le mot-clé this
est lié à vnode.state
.
Les méthodes de cycle de vie ne sont appelées que comme effet secondaire d'un appel à m.render()
. Elles ne sont pas invoquées si le DOM est modifié en dehors de Mithril.
Le cycle de vie d'un élément DOM
Un élément DOM est généralement créé et ajouté au document. Il peut ensuite avoir des attributs ou des nœuds enfants mis à jour lorsqu'un événement d'interface utilisateur est déclenché et que les données sont modifiées ; et l'élément peut également être supprimé du document.
Une fois qu'un élément est supprimé, il peut être temporairement conservé dans un pool de mémoire. L'élément mis en pool peut être réutilisé lors d'une mise à jour ultérieure (dans un processus appelé recyclage du DOM). Le recyclage d'un élément évite le coût de performance lié à la recréation d'une copie d'un élément qui existait récemment.
oninit
Le hook oninit(vnode)
est appelé avant qu'un vnode ne soit traité par le moteur du DOM virtuel. Il est garanti que oninit
s'exécute avant que son élément DOM ne soit attaché au document, et il est garanti qu'il s'exécute sur les vnodes parents avant leurs enfants, mais il n'offre aucune garantie concernant l'existence d'éléments DOM ancêtres ou descendants. Vous ne devriez jamais accéder à vnode.dom
depuis la méthode oninit
.
Ce hook n'est pas appelé lorsqu'un élément est mis à jour, mais il est appelé si un élément est recyclé.
Comme dans les autres hooks, le mot-clé this
dans le callback oninit
pointe vers vnode.state
.
Le hook oninit
est utile pour initialiser l'état du composant en fonction des arguments passés via vnode.attrs
ou vnode.children
.
function ComponentWithState() {
var initialData;
return {
oninit: function (vnode) {
initialData = vnode.attrs.data;
},
view: function (vnode) {
return [
// affiche les données du moment de l'initialisation :
m('div', 'Initial : ' + initialData),
// affiche les données actuelles :
m('div', 'Current : ' + vnode.attrs.data),
];
},
};
}
m(ComponentWithState, { data: 'Hello' });
Vous ne devriez pas modifier les données du modèle de manière synchrone à partir de cette méthode. Étant donné que oninit
ne donne aucune garantie concernant l'état des autres éléments, les modifications du modèle créées à partir de cette méthode peuvent ne pas être reflétées dans toutes les parties de l'interface utilisateur avant le prochain cycle de rendu.
oncreate
Le hook oncreate(vnode)
est appelé après la création d'un élément DOM et son rattachement au document. Il est garanti que oncreate
s'exécute à la fin du cycle de rendu, il est donc possible de lire en toute sécurité les valeurs de mise en page telles que vnode.dom.offsetHeight
et vnode.dom.getBoundingClientRect()
dans cette méthode.
Ce hook n'est pas appelé lorsqu'un élément est mis à jour.
Comme dans les autres hooks, le mot-clé this
dans le callback oncreate
pointe vers vnode.state
. Les éléments DOM dont les vnodes ont un hook oncreate
ne sont pas recyclés.
Le hook oncreate
est utile pour lire les valeurs de mise en page qui peuvent provoquer un repaint, démarrer des animations et pour initialiser des bibliothèques tierces qui nécessitent une référence à l'élément DOM.
var HeightReporter = {
oncreate: function (vnode) {
console.log('Initialisé avec une hauteur de : ', vnode.dom.offsetHeight);
},
view: function () {},
};
m(HeightReporter, { data: 'Hello' });
Vous ne devriez pas modifier les données du modèle de manière synchrone à partir de cette méthode. Étant donné que oncreate
est exécuté à la fin du cycle de rendu, les modifications du modèle ne seront pas reflétées dans l'interface utilisateur avant le prochain cycle de rendu.
onupdate
Le hook onupdate(vnode)
est appelé après la mise à jour d'un élément DOM, alors qu'il est attaché au document. Il est garanti que onupdate
s'exécute à la fin du cycle de rendu, il est donc possible de lire en toute sécurité les valeurs de mise en page telles que vnode.dom.offsetHeight
et vnode.dom.getBoundingClientRect()
dans cette méthode.
Ce hook n'est appelé que si l'élément existait lors du cycle de rendu précédent. Il n'est pas appelé lorsqu'un élément est créé ou lorsqu'il est recyclé.
Les éléments DOM dont les vnodes ont un hook onupdate
ne sont pas recyclés.
Le hook onupdate
est utile pour lire les valeurs de mise en page qui peuvent provoquer un repaint, et pour mettre à jour dynamiquement l'état affectant l'interface utilisateur dans des bibliothèques tierces suite à la modification des données du modèle.
function RedrawReporter() {
var count = 0;
return {
onupdate: function () {
console.log('Redessinages effectués : ', ++count);
},
view: function () {},
};
}
m(RedrawReporter, { data: 'Hello' });
onbeforeremove
Le hook onbeforeremove(vnode)
est appelé avant qu'un élément DOM ne soit détaché du document. Si une Promise est renvoyée, Mithril.js attend la résolution de la promise avant de détacher l'élément DOM.
Ce hook n'est appelé que sur l'élément DOM qui perd son parentNode
, mais il n'est pas appelé sur ses éléments enfants.
Comme dans les autres hooks, le mot-clé this
dans le callback onbeforeremove
pointe vers vnode.state
. Les éléments DOM dont les vnodes ont un hook onbeforeremove
ne sont pas recyclés.
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
Le hook onremove(vnode)
est appelé avant qu'un élément DOM ne soit supprimé du document. Si un hook onbeforeremove
est également défini, le hook onremove
s'exécute après la résolution de la promise renvoyée par onbeforeremove
.
Ce hook est appelé sur tout élément qui est supprimé du document, qu'il ait été directement détaché de son parent ou qu'il soit un enfant d'un autre élément qui a été détaché.
Comme dans les autres hooks, le mot-clé this
dans le callback onremove
pointe vers vnode.state
. Les éléments DOM dont les vnodes ont un hook onremove
ne sont pas recyclés.
Le hook onremove
est utile pour exécuter des tâches de nettoyage.
function Timer() {
var timeout = setTimeout(function () {
console.log('délai dépassé : ');
}, 1000);
return {
onremove: function () {
clearTimeout(timeout);
},
view: function () {},
};
}
onbeforeupdate
Le hook onbeforeupdate(vnode, old)
est appelé avant qu'un vnode ne soit comparé lors d'une mise à jour. Si cette fonction est définie et renvoie false
, Mithril.js empêche la comparaison du vnode, et par conséquent, celle des enfants du vnode.
Ce hook n'empêche pas la génération d'un sous-arbre du DOM virtuel, sauf si le sous-arbre est encapsulé dans un composant.
Comme dans les autres hooks, le mot-clé this
dans le callback onbeforeupdate
pointe vers vnode.state
.
Ce hook est utile pour réduire le ralentissement lors des mises à jour dans les cas où il existe un arbre DOM excessivement grand.
Éviter les anti-modèles
Bien que Mithril.js soit flexible, certains modèles de code sont à éviter :
Éviter les optimisations prématurées
Vous ne devriez utiliser onbeforeupdate
pour ignorer la comparaison qu'en dernier recours. Évitez de l'utiliser à moins que vous n'ayez un problème de performance notable.
En général, les problèmes de performance qui peuvent être corrigés grâce à onbeforeupdate
se résument à un grand tableau d'éléments. Dans ce contexte, « grand » signifie tout tableau qui contient un grand nombre de nœuds, que ce soit dans une large diffusion (le fameux tableau de 5000 lignes), ou dans un arbre profond et dense.
Si vous avez un problème de performance, demandez-vous d'abord si l'interface utilisateur offre une bonne expérience à l'utilisateur et modifiez-la si ce n'est pas le cas. Par exemple, il est très peu probable qu'un utilisateur passe au crible 5000 lignes de données brutes de tableau, et il est très probable qu'il soit plus facile pour un utilisateur d'utiliser une fonction de recherche qui ne renvoie que les quelques éléments les plus pertinents.
Si une solution basée sur la conception n'est pas réalisable et que vous devez optimiser une interface utilisateur avec un grand nombre d'éléments DOM, appliquez onbeforeupdate
sur le nœud parent du plus grand tableau et réévaluez les performances. Dans la grande majorité des cas, une seule vérification devrait suffire. Dans les rares cas où ce n'est pas le cas, répétez l'opération, mais vous devriez être de plus en plus méfiant à l'égard de chaque nouvelle déclaration onbeforeupdate
. Plusieurs onbeforeupdate
sont un signe de mauvaise qualité du code qui indique des problèmes de priorisation dans le flux de travail de conception.
Évitez d'appliquer cette optimisation à d'autres parties de votre application par précaution. N'oubliez pas que, d'une manière générale, plus de code entraîne un coût de maintenance plus élevé que moins de code. De plus, les bogues liés à onbeforeupdate
peuvent être particulièrement difficiles à résoudre si vous vous fiez à l'identité de l'objet pour vos vérifications conditionnelles.
Encore une fois, le hook onbeforeupdate
ne doit être utilisé qu'en dernier recours.