Guide pratique pour utiliser les fonctionnalités d’audience dans l’infrastructure Fluid
Dans ce tutoriel, vous allez découvrir comment utiliser l’infrastructure Fluid Audience avec React pour créer une démonstration visuelle des utilisateurs qui se connectent à un conteneur. L’objet d’audience contient des informations relatives à tous les utilisateurs connectés au conteneur. Dans cet exemple, la bibliothèque cliente Azure est utilisée pour créer le conteneur et l’audience.
L’image suivante montre des boutons d’ID et un champ d’entrée d’ID de conteneur. En laissant le champ d’ID de conteneur vide et en cliquant sur un bouton d’ID utilisateur, vous créez un conteneur et le rejoignez en tant qu’utilisateur sélectionné. L’utilisateur final peut également entrer un ID de conteneur et choisir un ID utilisateur pour joindre un conteneur existant en tant qu’utilisateur sélectionné.
L’image suivante montre plusieurs utilisateurs connectés à un conteneur représenté par des zones. La zone en bleu représente l’utilisateur qui affiche le client, tandis que les zones en noir représentent les autres utilisateurs connectés. À mesure que de nouveaux utilisateurs s’attachent au conteneur avec des ID uniques, le nombre de zones augmente.
Remarque
Ce tutoriel part du principe que vous êtes familiarisé avec la Vue d’ensemble de l’infrastructure Fluid et que vous avez terminé le démarrage rapide. Vous devez également être familiarisé avec les principes de base de React, la création de projets React et les hooks React.
Créer le projet
Ouvrez une invite de commandes et accédez au dossier parent dans lequel vous souhaitez créer le projet. Par exemple,
C:\My Fluid Projects
.Exécutez la commande suivante à l’invite. (Notez que l’interface CLI est npx, et non npm. Elle a été installée lorsque vous avez installé Node.js.)
npx create-react-app fluid-audience-tutorial
Le projet est créé dans un sous-dossier nommé
fluid-audience-tutorial
. Accédez-y avec la commandecd fluid-audience-tutorial
.Le projet utilise les bibliothèques Fluid suivantes :
Bibliothèque Description fluid-framework
Contient la structure de données distribuées SharedMap qui synchronise les données entre les clients. @fluidframework/azure-client
Définit la connexion à un serveur de service Fluid et définit le schéma de départ pour le conteneur Fluid. @fluidframework/test-client-utils
Définit l’élément InsecureTokenProvider nécessaire pour créer la connexion à un service Fluid. Exécutez la commande suivante pour installer les bibliothèques.
npm install @fluidframework/azure-client @fluidframework/test-client-utils fluid-framework
Coder le projet
Configurer les variables d’état et la vue des composants
Ouvrez le fichier
\src\App.js
dans l’éditeur de code. Supprimez toutes les instructionsimport
par défaut. Supprimez ensuite tout le balisage de l’instructionreturn
. Ajoutez ensuite des instructions d’importation pour les composants et hooks React. Notez que nous allons implémenter les composants AudienceDisplay et UserIdSelection importés dans les étapes ultérieures. Le fichier doit se présenter comme suit :import { useState, useCallback } from "react"; import { AudienceDisplay } from "./AudienceDisplay"; import { UserIdSelection } from "./UserIdSelection"; export const App = () => { // TODO 1: Define state variables to handle view changes and user input return ( // TODO 2: Return view components ); }
Remplacez
TODO 1
par le code suivant. Ce code initialise les variables d’état locales qui seront utilisées dans l’application. La valeurdisplayAudience
détermine si nous restituons le composant AudienceDisplay ou le composant UserIdSelection (voirTODO 2
). La valeuruserId
est l’identificateur utilisateur avec lequel se connecter au conteneur et la valeurcontainerId
est le conteneur à charger. Les fonctionshandleSelectUser
ethandleContainerNotFound
sont passées en tant que rappels aux deux vues et gèrent les transitions d’état.handleSelectUser
est appelé lors de la tentative de création/chargement d’un conteneur.handleContainerNotFound
est appelé en cas d’échec de la création/du chargement d’un conteneur.Notez que les valeurs userId et containerId proviennent d’un composant UserIdSelection via la fonction
handleSelectUser
.const [displayAudience, setDisplayAudience] = useState(false); const [userId, setUserId] = useState(); const [containerId, setContainerId] = useState(); const handleSelectUser = useCallback((userId, containerId) => { setDisplayAudience(true) setUserId(userId); setContainerId(containerId); }, [displayAudience, userId, containerId]); const handleContainerNotFound = useCallback(() => { setDisplayAudience(false) }, [setDisplayAudience]);
Remplacez
TODO 2
par le code suivant. Comme indiqué ci-dessus, la variabledisplayAudience
détermine si nous restituons le composant AudienceDisplay ou le composant UserIdSelection. En outre, les fonctions permettant de mettre à jour les variables d’état sont passées aux composants en tant que propriétés.(displayAudience) ? <AudienceDisplay userId={userId} containerId={containerId} onContainerNotFound={handleContainerNotFound}/> : <UserIdSelection onSelectUser={handleSelectUser}/>
Configurer le composant AudienceDisplay
Créez et ouvrez un fichier
\src\AudienceDisplay.js
dans l’éditeur de code. Ajoutez les instructionsimport
suivantes :import { useEffect, useState } from "react"; import { SharedMap } from "fluid-framework"; import { AzureClient } from "@fluidframework/azure-client"; import { InsecureTokenProvider } from "@fluidframework/test-client-utils";
Notez que les objets importés à partir de la bibliothèque de l’infrastructure Fluid sont requis pour définir des utilisateurs et des conteneurs. Dans les étapes suivantes, AzureClient et InsecureTokenProvider seront utilisés pour configurer le service client (voir
TODO 1
) tandis que SharedMap sera utilisé pour configurer uncontainerSchema
nécessaire pour créer un conteneur (voirTODO 2
).Ajoutez les composants fonctionnels et les fonctions d’assistance suivants :
const tryGetAudienceObject = async (userId, userName, containerId) => { // TODO 1: Create container and return audience object } export const AudienceDisplay = (props) => { //TODO 2: Configure user ID, user name, and state variables //TODO 3: Set state variables and set event listener on component mount //TODO 4: Return list view } const AudienceList = (data) => { //TODO 5: Append view elements to list array for each member //TODO 6: Return list of member elements }
Notez que AudienceDisplay et AudienceList sont des composants fonctionnels qui gèrent l’obtention et le rendu des données d’audience, tandis que la méthode
tryGetAudienceObject
gère la création de services de conteneur et d’audience.
Obtention d’un conteneur et d’une audience
Vous pouvez utiliser une fonction d’assistance pour obtenir les données Fluid de l’objet Audience dans la couche d’affichage (état React). La méthode tryGetAudienceObject
est appelée lorsque le composant d’affichage se charge après la sélection d’un ID utilisateur. La valeur retournée est affectée à une propriété d’état React.
Remplacez
TODO 1
par le code suivant. Notez que les valeurs pouruserId
userName
containerId
devront être transmises à partir du composant App. S’il n’y a pascontainerId
, un nouveau conteneur est créé. Notez également que estcontainerId
stocké sur le hachage d’URL. Un utilisateur qui entre dans une session à partir d’un nouveau navigateur peut copier l’URL à partir d’un navigateur de session existant ou accéder àlocalhost:3000
l’ID de conteneur et entrer manuellement. Avec cette implémentation, nous voulons encapsuler l’appelgetContainer
dans un test catch dans le cas où l’utilisateur entre un ID de conteneur qui n’existe pas. Pour plus d’informations, consultez la documentation conteneurs .const userConfig = { id: userId, name: userName, additionalDetails: { email: userName.replace(/\s/g, "") + "@example.com", date: new Date().toLocaleDateString("en-US"), }, }; const serviceConfig = { connection: { type: "local", tokenProvider: new InsecureTokenProvider("", userConfig), endpoint: "http://localhost:7070", }, }; const client = new AzureClient(serviceConfig); const containerSchema = { initialObjects: { myMap: SharedMap }, }; let container; let services; if (!containerId) { ({ container, services } = await client.createContainer(containerSchema)); const id = await container.attach(); location.hash = id; } else { try { ({ container, services } = await client.getContainer(containerId, containerSchema)); } catch (e) { return; } } return services.audience;
Obtention de l’audience sur le montage du composant
Maintenant que nous avons défini comment obtenir l’audience Fluid, nous devons indiquer à React d’appeler tryGetAudienceObject
quand le composant Affichage d’audience est monté.
Remplacez
TODO 2
par le code suivant. Notez que l’ID utilisateur provient du composant parent en tant queuser1
user2
random
ou . Si l’ID estrandom
, nous utilisonsMath.random()
pour générer un nombre aléatoire comme ID. En outre, un nom est mappé à l’utilisateur en fonction de son ID, comme spécifié dansuserNameList
. Enfin, nous définissons les variables d’état qui stockent les membres connectés ainsi que l’utilisateur actuel.fluidMembers
stocke la liste de tous les membres connectés au conteneur, tandis quecurrentMember
contient l’objet membre représentant l’utilisateur actuel qui affiche le contexte du navigateur.const userId = props.userId == "random" ? Math.random() : props.userId; const userNameList = { "user1" : "User One", "user2" : "User Two", "random" : "Random User" }; const userName = userNameList[props.userId]; const [fluidMembers, setFluidMembers] = useState(); const [currentMember, setCurrentMember] = useState();
Remplacez
TODO 3
par le code suivant. Cette opération appelletryGetAudienceObject
lorsque le composant est monté, et définit les membres d’audience retournés surfluidMembers
etcurrentMember
. Notez que nous vérifions si un objet d’audience est retourné au cas où un utilisateur entre un containerId qui n’existe pas et nous devons les renvoyer à la vue UserIdSelection (props.onContainerNotFound()
gérera le changement d’affichage). En outre, il est recommandé d’annuler l’inscription des gestionnaires d’événements lorsque le composant React se démonte en retournantaudience.off
.useEffect(() => { tryGetAudienceObject(userId, userName, props.containerId).then(audience => { if(!audience) { props.onContainerNotFound(); alert("error: container id not found."); return; } const updateMembers = () => { setFluidMembers(audience.getMembers()); setCurrentMember(audience.getMyself()); } updateMembers(); audience.on("membersChanged", updateMembers); return () => { audience.off("membersChanged", updateMembers) }; }); }, []);
Remplacez
TODO 4
par le code suivant. Notez que sifluidMembers
oucurrentMember
n’a pas été initialisé, un écran vide est affiché. Le composant AudienceList affiche les données des membres avec un style (à implémenter dans la section suivante).if (!fluidMembers || !currentMember) return (<div/>); return ( <AudienceList fluidMembers={fluidMembers} currentMember={currentMember}/> )
Remarque
Les transitions de connexion peuvent entraîner des fenêtres courtes où
getMyself
retourneundefined
. Cela est dû au fait que la connexion cliente actuelle n’a pas encore été ajoutée à l’audience, de sorte qu’un ID de connexion correspondant est introuvable. Pour empêcher React de rendre une page sans membres d’audience, nous ajoutons un écouteur pour appelerupdateMembers
surmembersChanged
. Cela fonctionne, car l’audience du service émet un événementmembersChanged
lorsque le conteneur est connecté.
Créer l’affichage
Remplacez
TODO 5
par le code suivant. Notez que nous exécutons un composant de liste pour chaque membre passé à partir du composant AudienceDisplay. Pour chaque membre, nous comparons d’abordmember.userId
àcurrentMember.userId
pour vérifier si ce membreisSelf
. De cette façon, nous pouvons différencier l’utilisateur client des autres utilisateurs et afficher le composant avec une couleur différente. Nous envoyons ensuite le composant de liste à un tableaulist
. Chaque composant affiche les données membres telles queuserId
userName
etadditionalDetails
.const currentMember = data.currentMember; const fluidMembers = data.fluidMembers; const list = []; fluidMembers.forEach((member, key) => { const isSelf = (member.userId === currentMember.userId); const outlineColor = isSelf ? 'blue' : 'black'; list.push( <div style={{ padding: '1rem', margin: '1rem', display: 'flex', outline: 'solid', flexDirection: 'column', maxWidth: '25%', outlineColor }} key={key}> <div style={{fontWeight: 'bold'}}>Name</div> <div> {member.userName} </div> <div style={{fontWeight: 'bold'}}>ID</div> <div> {member.userId} </div> <div style={{fontWeight: 'bold'}}>Connections</div> { member.connections.map((data, key) => { return (<div key={key}>{data.id}</div>); }) } <div style={{fontWeight: 'bold'}}>Additional Details</div> { JSON.stringify(member.additionalDetails, null, '\t') } </div> ); });
Remplacez
TODO 6
par le code suivant. Cela rendra tous les éléments membres que nous avons poussés dans le tableaulist
.return ( <div> {list} </div> );
Configurer le composant UserIdSelection
Créez et ouvrez un fichier
\src\UserIdSelection.js
dans l’éditeur de code. Ce composant inclut des boutons d’ID utilisateur et des champs d’entrée d’ID de conteneur qui permettent aux utilisateurs finaux de choisir leur ID utilisateur et leur session collaborative. Ajoutez les instructionsimport
et les composants fonctionnels suivants :import { useState } from 'react'; export const UserIdSelection = (props) => { // TODO 1: Define styles and handle user inputs return ( // TODO 2: Return view components ); }
Remplacez
TODO 1
par le code suivant. Notez que la fonctiononSelectUser
met à jour les variables d’état dans le composant Application parent et demande une modification de vue. La méthodehandleSubmit
est déclenchée par des éléments de bouton qui seront implémentés dansTODO 2
. En outre, la méthodehandleChange
est utilisée pour mettre à jour la variable d’étatcontainerId
. Cette méthode est appelée à partir d’un écouteur d’événement d’élément d’entrée implémenté dansTODO 2
. Notez également que nous mettons à jour lecontainerId
avec la valeur à partir d’un élément HTML avec l’IDcontainerIdInput
(défini dansTODO 2
).const selectionStyle = { marginTop: '2rem', marginRight: '2rem', width: '150px', height: '30px', }; const [containerId, setContainerId] = (location.hash.substring(1)); const handleSubmit = (userId) => { props.onSelectUser(userId, containerId); } const handleChange = () => { setContainerId(document.getElementById("containerIdInput").value); };
Remplacez
TODO 2
par le code suivant. Cela permet d’afficher les boutons d’ID utilisateur ainsi que le champ d’entrée d’ID de conteneur.<div style={{display: 'flex', flexDirection:'column'}}> <div style={{marginBottom: '2rem'}}> Enter Container Id: <input type="text" id="containerIdInput" value={containerId} onChange={() => handleChange()} style={{marginLeft: '2rem'}}></input> </div> { (containerId) ? (<div style={{}}>Select a User to join container ID: {containerId} as the user</div>) : (<div style={{}}>Select a User to create a new container and join as the selected user</div>) } <nav> <button type="submit" style={selectionStyle} onClick={() => handleSubmit("user1")}>User 1</button> <button type="submit" style={selectionStyle} onClick={() => handleSubmit("user2")}>User 2</button> <button type="submit" style={selectionStyle} onClick={() => handleSubmit("random")}>Random User</button> </nav> </div>
Démarrer le serveur Fluid et exécuter l’application
Remarque
Pour correspondre au reste de cette procédure, cette section utilise les commandes npx
et npm
pour démarrer un serveur Fluid. Toutefois, le code de cet article peut également s’exécuter sur un serveur Relais Azure Fluid. Pour plus d’informations, consultez Guide pratique : Provisionner un service Relais Azure Fluid et Guide pratique : Se connecter à un service Relais Azure Fluid
Dans l’invite de commandes, exécutez la commande suivante pour démarrer le service Fluid.
npx @fluidframework/azure-local-service@latest
Ouvrez une nouvelle invite de commandes et accédez à la racine du projet. par exemple C:/My Fluid Projects/fluid-audience-tutorial
. Démarrez le serveur d’application à l’aide de la commande suivante. L’application s’ouvre dans le navigateur. Cela peut prendre quelques minutes.
npm run start
Accédez à localhost:3000
sur un onglet de navigateur pour afficher l’application en cours d’exécution. Pour créer un conteneur, sélectionnez un bouton d’ID utilisateur tout en laissant l’entrée d’ID de conteneur vide. Pour simuler un nouvel utilisateur qui rejoint la session de conteneur, ouvrez un nouvel onglet de navigateur et accédez à localhost:3000
. Cette fois, entrez la valeur de l’ID de conteneur, qui se trouve dans l’URL du premier onglet du navigateur, après http://localhost:3000/#
.
Remarque
Vous devrez peut-être installer une dépendance supplémentaire pour rendre cette démonstration compatible avec Webpack 5. Si vous recevez une erreur de compilation liée à un package « buffer » ou « url », exécutez npm install -D buffer url
et réessayez. Ce problème sera résolu dans une version ultérieure de l’infrastructure Fluid.
Étapes suivantes
- Essayez d’étendre la démonstration avec d’autres paires clé/valeur dans le champ
additionalDetails
dansuserConfig
. - Envisagez d’intégrer l’audience dans une application collaborative qui utilise des structures de données distribuées, comme SharedMap ou SharedString.
- En savoir plus sur Audience.
Conseil
Lorsque vous apportez des modifications au code, le projet est automatiquement régénéré et le serveur d’applications est rechargé. Toutefois, si vous apportez des modifications au schéma du conteneur, elles ne prendront effet que si vous fermez et redémarrez le serveur d’applications. Pour ce faire, rendez l’invite de commandes focale et appuyez deux fois sur Ctrl+C. Puis exécutez npm run start
à nouveau.