Messages et Replicants : communiquer dans NodeCG
Pour faire le lien entre les différentes parties d’un bundle et permettre la transmission d’informations, NodeCG propose principalement deux mécanismes : les Replicants et les Messages.
Ils permettent tous les deux de faire communiquer les différents contextes (les éléments du dashboard, des Graphic, de l’extension) d’un bundle, mais ils ne répondent pas au même besoin.
- Les
Replicants: partager un état ou une valeur. - Les
Messages: transmettre un événement ou déclencher une action.
Une façon simple de les retenir :
Replicant → “Voici la valeur actuelle.”
Message → “Il vient de se passer quelque chose.” / “Fais ceci.”
Les deux permettent de faire communiquer les différentes parties d’un bundle, mais ils ne répondent pas au même besoin.
Les Replicants
Section titled “Les Replicants”Un Replicant permet de partager une donnée entre les différents contextes d’un bundle NodeCG, avec deux principaux avantages.
- Une source de vérité
On peut le considérer comme une source de vérité pour une donnée partagée : plusieurs parties de l’application travaillent autour de la même valeur.
Par exemple, si le Dashboard modifie le score de l’équipe 1, les autres contextes qui utilisent ce Replicant sont automatiquement informés de cette modification.
Les Replicants sont particulièrement adaptés aux données qui représentent un état actuel :
- le score actuel
- le nom des équipes
- la visibilité du scoreboard
- le joueur actuellement affiché
- …
- La persistance des données
Un autre intérêt majeur est la persistance des valeurs.
Par défaut, un Replicant est persistant : sa valeur peut être conservée lorsque l’on recharge une page et même lorsque NodeCG est redémarré.
Imaginons que votre Dashboard affiche un score de 3 - 1.
Si vous rechargez la page, le Replicant permet au Dashboard de retrouver l’état actuel du score plutôt que de repartir de zéro.
La forme d’un Replicant
Section titled “La forme d’un Replicant”Voici un exemple de Replicant utilisé pour gérer le scoreboard :
const scoreboardRep = nodecg.Replicant("scoreboardRep", { defaultValue: { team1: { name: "Team 1", score: 0, }, team2: { name: "Team 2", score: 0, }, isVisible: true, }, persistent: true,});Un Replicant a un nom (libre à vous de choisir) et peut contenir différents types de données : une chaîne de caractères, un nombre, un booléen, un tableau ou encore un objet plus complexe.
Ici, defaultValue définit l’état initial du scoreboard, les valeurs par défaut qui s’afficheront si rien n’est indiqué :
Le contenu de defaultValue est entièrement libre : c’est à vous de définir la structure de données dont votre application a besoin.
Dans notre exemple, j’ai choisi de représenter le scoreboard avec :
- deux équipes, chacune avec un nom et un score
- une propriété
isVisiblepermettant de savoir si le scoreboard doit être affiché
Mais team1, team2, name, score et isVisible ne sont pas des propriétés particulières de NodeCG. Ce sont simplement les propriétés que j’ai choisies pour structurer les données de mon scoreboard.
J’aurais tout aussi bien pu utiliser une structure différente :
const scoreRep = nodecg.Replicant("scoreRep", {defaultValue: { home: { label: "Team 1", points: 0, }, away: { label: "Team 2", points: 0, }, isDisplayed: true,} persistent: true,});NodeCG ne se préoccupe pas de savoir comment vous organisez ces données : il se charge de partager la valeur du Replicant entre les différents contextes. La structure et le contenu de cette valeur dépendent de votre application.
La propriété persistent, en revanche, est une option fournie par NodeCG. Elle indique si la valeur du Replicant doit être conservée.
Elle est activée par défaut, il est donc rarement nécessaire de la préciser explicitement. Dans certains cas, notamment pour des données temporaires qui ne doivent pas être conservées après un redémarrage, on peut utiliser persistent: false.
Utiliser un Replicant
Section titled “Utiliser un Replicant”Dans la pratique, l’utilisation d’un Replicant repose généralement sur trois étapes :
- déclarer le
Replicant - modifier sa valeur
- réagir aux changements
On peut résumer cela ainsi :
Je déclare une donnée partagée → je modifie sa valeur → les autres contextes réagissent au changement.
Déclarer le Replicant
Section titled “Déclarer le Replicant”Il faut déclarer le Replicant dans chaque contexte (chaque élement de Dashboard, Graphics ou Extension) qui doit l’utiliser.
Dans le bundle d’initiation, par exemple, scoreboardRep est déclaré à la fois dans le Dashboard et dans le Graphic.
C’est d’ailleurs une erreur classique lorsqu’on débute : déclarer le Replicant une seule fois en pensant que cela suffit. Au contraire, chaque contexte doit récupérer le Replicant qu’il souhaite utiliser.
Modifier sa valeur
Section titled “Modifier sa valeur”Une fois le Replicant déclaré, on peut modifier sa valeur.
Dans la pratique, c’est souvent la partie Dashboard ou Extension qui modifie les Replicants, tandis que les Graphics se contentent principalement de les lire pour mettre à jour leur affichage.
Ce n’est cependant pas une règle imposée par NodeCG : n’importe quel contexte peut modifier un Replicant auquel il a accès.
Dans notre bundle d’initiation, il est possible de modifier les scores des équipes avec les boutons + et -. Ainsi, lorsque l’on clique sur le bouton + de l’équipe 1, on incrémente simplement la valeur de “1” dans le Replicant
document.getElementById("t1Plus").addEventListener("click", () => { scoreboardRep.value.team1.score++; // On incrémente la valeur de 1 dans le Replicant});La valeur du score est directement modifiée dans le Replicant et cette modification est ensuite répliquée dans les autres contextes qui utilisent ce même Replicant.
Réagir aux changements
Section titled “Réagir aux changements”Un contexte peut écouter les modifications d’un Replicant grâce à l’événement “change” :
scoreboardRep.on("change", (value) => { // Mettre à jour l'interface ou le Graphic});Ici, chaque fois que la valeur du Replicant change, la fonction est appelée avec la nouvelle valeur.
Dans un Dashboard, on peut par exemple s’en servir pour mettre à jour les champs d’un formulaire, dans un Graphic, on pourra mettre à jour l’affichage à l’écran :
scoreboardRep.on("change", (value) => { team1Score.textContent = value.team1.score; team2Score.textContent = value.team2.score;});Le Graphic n’a donc pas besoin de savoir pourquoi le score a changé. Il lui suffit de réagir au nouvel état du Replicant.
Les Messages
Section titled “Les Messages”Pourquoi ne pas utiliser un Replicant pour tout ?
Section titled “Pourquoi ne pas utiliser un Replicant pour tout ?”Jusqu’ici, nous avons surtout parlé de données qui représentent un état : le score actuel, le nom des équipes ou encore la visibilité du scoreboard.
Cependant, toutes les informations qui circulent dans une application ne représentent pas forcément un état. Parfois, on veut simplement prévenir un autre contexte que quelque chose vient de se produire.
Par exemple :
“L’équipe 1 vient de marquer, joue l’animation !”
Dans ce cas, il n’est pas forcément pertinent de créer un Replicant pour l’animation et de modifier sa valeur, car nous ne cherchons pas à stocker un état : nous voulons simplement déclencher une action à un instant précis.
C’est là que les Messages entrent en jeu.
Un Message, c’est quoi ?
Section titled “Un Message, c’est quoi ?”Un Message peut être vu comme un signal ponctuel envoyé d'un contexte à un autre. Un contexte envoie le message, et un autre contexte peut l’écouter et réagir.
Dans NodeCG, cela se fait principalement avec deux méthodes :
nodecg.sendMessage()pour envoyer un messagenodecg.listenFor()pour écouter un message
Par exemple, imaginons que le Dashboard possède un bouton permettant de lancer une animation dans le Graphic.
Le Dashboard peut envoyer le message :
nodecg.sendMessage("playAnimation");Le Graphic le récupère :
nodecg.listenFor("playAnimation", () => { // Message reçu, je déclenche l'animation});Lorsque le bouton est utilisé, le Dashboard envoie le message et le Graphic réagit immédiatement.
Il n’y a ici aucune donnée à conserver. Une fois le message reçu et traité, l’événement est terminé.
Un Message peut aussi transmettre des données
Section titled “Un Message peut aussi transmettre des données”Même si un Message sert principalement à signaler un événement ou à déclencher une action, il peut également transporter des données.
Par exemple, plutôt que de simplement dire au Graphic « joue l’animation », le Dashboard peut préciser quelle équipe vient de marquer :
nodecg.sendMessage("goalScored", { team: 1,}); nodecg.listenFor("goalScored", (data) => { if (data.team === 1) { // Jouer l'animation de l'équipe 1 }});Le Message transporte donc ici deux informations :
- l’événement :
goalScored - les données associées à cet événement
team: 1
Cela ne transforme pas pour autant le Message en Replicant. La différence tient surtout à ce que l’on cherche à représenter.
Dans cet exemple, team: 1 indique ce qui vient de se produire. Cette information accompagne l’événement et n’a pas vocation à représenter un état permanent.
Si, au contraire, on souhaite pouvoir demander à tout moment quelle équipe a le dernier score, cette information devrait plutôt être stockée dans un Replicant.
On peut donc retenir :
Un
Replicantpartage un état, éventuellement complexe.
Un
Messagesignale un événement, éventuellement accompagné de données.
Alors, Replicant ou Message ?
Section titled “Alors, Replicant ou Message ?”J’insiste une dernière fois là-dessus car ce n’est pas toujours évident de savoir lequel utiliser.
Les deux permettent de faire communiquer les différents contextes de NodeCG, mais ils ne représentent pas la même chose.
Une façon simple de faire son choix est de se poser une question :
Est-ce que je veux partager une donnée qui représente un état, ou est-ce que je veux déclencher quelque chose ?
Utilisez plutôt un Replicant lorsque…
Section titled “Utilisez plutôt un Replicant lorsque…”Votre élément a besoin de connaître la valeur ou l’état actuel d’une donnée.
Par exemple :
- quel est le score actuel ?
- quel est le nom de l’équipe ?
- le scoreboard est-il visible ?
- quel joueur est actuellement affiché ?
Dans ces situations, l’information représente un état qui peut être consulté ou modifié au fil du temps.
Utilisez plutôt un Message lorsque…
Section titled “Utilisez plutôt un Message lorsque…”Vous voulez signaler qu’un événement vient de se produire ou demander à un autre contexte d’effectuer une action ponctuelle.
Par exemple :
- lancer une animation
- jouer un son
- afficher une notification
- déclencher une transition
- demander à un autre contexte d’effectuer une action ponctuelle
Dans ces situations, on ne cherche pas à conserver l’événement. On veut simplement prévenir un autre contexte que quelque chose vient de se produire ou lui demander de faire quelque chose.
Dans notre scoreboard :
- le score
3 - 1est un état : il a donc naturellement sa place dans unReplicant. - si l’on veut déclencher une animation lorsque l’équipe 1 marque, c’est un événement, donc un
Message