La Réactivité

Aparté 6.5

Traduction complétée à

Au programme de ce chapitre :

  • En apprendre plus sur le système de dépendance du code réactif de Meteor.
  • Comprendre les motivations et la manière dont il rend le code déclaratif.
  • Apprendre à écrire du code avancé qui utilise des données réactives.
  • Si les collections sont la fonctionnalité principale de Meteor, la Réactivité est la coquille qui la rend utile.

    Les Collections transforment radicalement la façon dont votre application traite les modifications de données. Plutôt que d'avoir à vérifier les modifications de données manuellement (par un appel AJAX, par exemple) et de les mettre à jour dans votre page HTML, Meteor applique automatiquement ces modifications à votre interface utilisateur de façon transparente.

    Prenez un moment pour y penser : dans les coulisses, Meteor est capable de changer toute partie de votre interface utilisateur chaque fois qu'une collection sous-jacente est mise à jour.

    La meilleure façon de parvenir à cela serait d'utiliser .observe(), une fonction de curseur qui déclenche des callbacks lorsque des documents correspondant à ce curseur changent. Nous pourrions alors faire des changements dans le DOM (le rendu HTML de notre page Web) à travers ces callbacks. Le code résultant ressemblerait à quelque chose comme ceci :

    Posts.find().observe({
      added: function(post) {
        // quand le callback 'added' est déclenché, ajout de l'élément HTML
        $('ul').append('<li id="' + post._id + '">' + post.title + '</li>');
      },
      changed: function(post) {
        // quand le callback 'changed' est déclenché, modification du texte de l'élément HTML
        $('ul li#' + post._id).text(post.title);
      },
      removed: function(post) {
        // quand le callback 'removed' est déclenché, suppression de l'élément HTML
        $('ul li#' + post._id).remove();
      }
    });
    

    Vous pouvez probablement déjà voir comment le code va rapidement se complexifier. Imaginez comment traiter les modifications de chaque attribut de l'article, et devoir changer du HTML complexe à l'intérieur des <li> de l'article. Sans parler de tous les cas compliqués qui peuvent survenir quand nous commençons à gérer de multiples sources d'information qui peuvent toutes changer en temps réel.

    Quand devrions-nous utiliser observe() ?

    Utiliser le modèle ci-dessus est parfois nécessaire, spécialement quand on doit s'interfacer avec des gadgets tiers. Par exemple, imaginons que nous voulions ajouter ou supprimer sur une carte en temps réel des marqueurs basés sur des données d'une Collection (disons, pour afficher la localisation des utilisateurs authentifiés).

    Dans certains cas, vous aurez besoin d'utiliser des callbacks observe() afin de faire discuter la carte avec la collection Meteor et savoir comment réagir avec les changements de données. Par exemple, vous pourriez utiliser les callbacks added et removed pour appeler les propres méthodes dropPin() et removePin() de l'API carte.

    Une approche déclarative

    Meteor nous fournit un meilleur outil : la réactivité, qui est dans sa structure une approche déclarative. Être déclaratif nous laisse définir la relation entre les objets une fois et savoir qu'ils resteront synchronisés, au lieu de devoir spécifier les comportements pour tous les changements potentiels.

    Ceci est un concept puissant, parce qu'un système temps réel a beaucoup d'entrées qui peuvent changer à de façon imprévisible. En exposant déclarativement la façon dont nous affichons le HTML basé sur les sources de données réactives que nous observons, Meteor peut surveiller ces sources et accomplir de manière transparente ce travail de mise à jour permanente de l'interface utilisateur.

    Tout ceci pour dire qu'au lieu de réfléchir sur des callbacks observe(), Meteor nous permet d'écrire :

    <template name="postsList">
      <ul>
        {{#each posts}}
          <li>{{title}}</li>
        {{/each}}
      </ul>
    </template>
    

    Et ensuite récupérer notre liste d'articles avec :

    Template.postsList.helpers({
      posts: function() {
        return Posts.find();
      }
    });
    

    En arrière-plan, Meteor déclenche des callbacks observe() pour nous, et redéssine les sections pertinentes du HTML quand les données réactives changent.

    Surveillance de dépendance dans Meteor: Calculs (Computations)

    Alors que Meteor est un framework temps réel, réactif, tout le code à l'intérieur d'une application Meteor n'est pas réactif. Si c'était le cas, votre application entière se rechargerait à chaque fois qu'il y a un changement. À la place, la réactivité est limitée à des zones spécifiques de votre code, et nous appellerons ces zones calculs.

    En d'autres termes, un calcul est un bloc de code qui est exécuté à chaque fois qu'une des sources de données réactives dont il dépend change. Si vous avez une source de données réactive (par exemple, une variable de Session) et que vous aimeriez réagir de manière réactive, vous aurez besoin de mettre en place un calcul.

    Notez qu'habituellement vous n'avez pas besoin de faire ceci parce que Meteor donne déjà à chaque template et helper qu'il affiche son propre calcul (ce qui signifie que vous pouvez être sûr que vos templates seront réactifs à afficher leurs données sources).

    Chaque source de données réactive surveille tous les calculs qui l'utilisent pour qu'elle puisse les laisser savoir quand sa propre valeur change. Pour ce faire, il appelle la fonction invalidate() sur le calcul.

    Les calculs sont généralement mis en place pour réévaluer simplement leurs contenus sur invalidation, et c'est ce qui arrive aux calculs de template (bien que les calculs de template font également la magie d'essayer et redessiner la page plus efficacement). Bien que nous pouvons avoir plus de contrôle sur ce que fait le calcul sur invalidation si vous en avez besoin, en pratique c'est presque toujours le comportement que vous utiliserez.

    Mettre en place un Calcul

    Maintenant que nous comprenons la théorie derrière les calculs, en mettre un en place semble beaucoup plus sensé. Nous pouvons utiliser la fonction Tracker.autorun pour enfermer un bloc de code dans un calcul et le rendre réactif :

    Meteor.startup(function() {
      Tracker.autorun(function() {
        console.log('There are ' + Posts.find().count() + ' posts');
      });
    });
    

    Notez que nous avons besoin d'envelopper le bloc Tracker à l'intérieur d'un bloc Meteor.startup() pour nous assurer qu'il s'exécutera seulement une fois que Meteor a fini de charger la collection Posts.

    En arrière-plan, autorun crée ensuite un calcul, et le déclenche pour réévaluer à chaque fois que la source de données dont il dépend change. Nous avons mis en place un calcul vraiment très simple qui journalise simplement le nombre d'articles à la console. Maintenant que Posts.find() est une source de données réactive, il prendra soin de dire au calcul de réévaluer à chaque fois que le nombre d'articles change.

    > Posts.insert({title: 'New Post'});
    There are 4 posts.
    

    Le résultat net de tout ceci est que nous pouvons écrire du code qui utilise une donnée réactive de façon très naturelle, en sachant qu'en arrière-plan le système de dépendance prendra soin de le réexécuter juste au bon moment.