Verwenden von Zielgruppenfeatures im Fluid-Framework

In diesem Tutorial erfahren Sie, wie Sie eine Zielgruppe in Fluid Framework mit React verwenden, um eine visuelle Demonstration von Benutzer*innen, die eine Verbindung mit einem Container herstellen, zu erstellen. Das Zielgruppenobjekt enthält Informationen zu allen Benutzer*innen, die mit dem Container verbunden sind. In diesem Beispiel wird die Azure-Clientbibliothek zum Erstellen des Containers und der Zielgruppe verwendet.

Die folgende Abbildung zeigt ID-Schaltflächen und ein Container-ID-Eingabefeld. Wenn Sie das Feld für die Container-ID leer lassen und auf eine Benutzer*innen-ID-Schaltfläche klicken, wird ein neuer Container erstellt und als ausgewählte*r Benutzer*in eingebunden. Alternativ können die Endbenutzer*innen eine Container-ID eingeben und eine Benutzer-ID auswählen, um einen vorhandenen Container als ausgewählte*r Benutzer*in zu verknüpfen.

A screenshot of a browser with buttons for selecting a user.

Die nächste Abbildung zeigt mehrere durch Felder dargestellte Benutzer*innen, die mit einem Container verbunden sind. Das blau umrissene Feld stellt den oder die Benutzer*in dar, der bzw. die den Client anzeigt, während die schwarz umrissenen Felder die anderen verbundenen Benutzer*innen darstellen. Wenn neue Benutzer*innen mit eindeutigen IDs an den Container angefügt werden, erhöht sich die Anzahl der Felder.

A screenshot of a browser showing information for four different container users.

Hinweis

In diesem Tutorial wird davon ausgegangen, dass Sie mit der Übersicht über Fluid Framework vertraut sind und den Schnellstart abgeschlossen haben. Sie sollten auch mit den Grundlagen von React, dem Erstellen von React-Projekten und React-Hooks vertraut sein.

Erstellen des Projekts

  1. Öffnen Sie eine Eingabeaufforderung, und navigieren Sie zu dem übergeordneten Ordner, in dem Sie das Projekt erstellen möchten, z. B. C:\My Fluid Projects.

  2. Führen Sie an der Eingabeaufforderung den folgenden Befehl aus. (Beachten Sie, dass die Befehlszeilenschnittstelle npx und nicht npm heißt. Sie wurde beim Installieren von Node.js installiert.)

    npx create-react-app fluid-audience-tutorial
    
  3. Das Projekt wird in einem Unterordner mit dem Namen fluid-audience-tutorial erstellt. Navigieren Sie mit dem Befehl cd fluid-audience-tutorial zu ihm.

  4. Das Projekt verwendet die folgenden Fluid-Bibliotheken:

    Bibliothek Beschreibung
    fluid-framework Es enthält die verteilte Datenstruktur SharedMap, die Daten clientübergreifend synchronisiert.
    @fluidframework/azure-client Es definiert die Verbindung mit einem Fluid-Dienstserver und das Startschema für den Fluid-Container.
    @fluidframework/test-client-utils Es definiert den erforderlichen InsecureTokenProvider zum Erstellen der Verbindung mit einem Fluid-Dienst.

    Führen Sie den folgenden Befehl aus, um die Bibliotheken zu installieren.

    npm install @fluidframework/azure-client @fluidframework/test-client-utils fluid-framework
    

Programmieren des Projekts

Einrichten von Zustandsvariablen und der Komponentenansicht

  1. Öffnen Sie im Code-Editor die Datei \src\App.js. Löschen Sie alle import-Standardanweisungen. Löschen Sie dann das gesamte Markup aus der return-Anweisung. Fügen Sie anschließend Importanweisungen für Komponenten und React-Hooks hinzu. Beachten Sie, dass die importierten AudienceDisplay - und UserIdSelection-Komponenten in den späteren Schritten implementiert werden. Die Datei sollte folgendermaßen aussehen:

        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
        );
        }
    
  2. Ersetzen Sie TODO 1 durch den folgenden Code. Dieser Code initialisiert lokale Zustandsvariablen, die in der Anwendung verwendet werden. Der Wert displayAudience legt fest, ob die Komponente AudienceDisplay oder UserIdSelection gerendert wird (siehe TODO 2). Der Wert userId ist der Benutzerbezeichner für die Verbindung mit dem Container, und der Wert containerId ist der zu ladende Container. Die Funktionen handleSelectUser und handleContainerNotFound werden als Rückrufe an die beiden Ansichten übergeben und verwalten Zustandsübergänge. handleSelectUser wird aufgerufen, wenn versucht wird, einen Container zu erstellen/zu laden. handleContainerNotFound wird aufgerufen, wenn beim Erstellen/Laden eines Containers ein Fehler auftritt.

    Beachten Sie, dass die Werte „userId“ und „containerId“ von einer UserIdSelection-Komponente über die handleSelectUser-Funktion abgerufen werden.

        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]);
    
  3. Ersetzen Sie TODO 2 durch den folgenden Code. Wie oben erwähnt, legt die Variable displayAudience fest, welche der Komponenten AudienceDisplay oder UserIdSelection gerendert wird. Außerdem werden Funktionen zum Aktualisieren der Zustandsvariablen als Eigenschaften an die Komponenten übergeben.

        (displayAudience) ?
        <AudienceDisplay userId={userId} containerId={containerId} onContainerNotFound={handleContainerNotFound}/> :
        <UserIdSelection onSelectUser={handleSelectUser}/>
    

Einrichten der Komponente AudienceDisplay

  1. Erstellen Sie die Datei \src\AudienceDisplay.js, und öffnen Sie sie im Code-Editor. Fügen Sie die folgenden import -Anweisungen ein:

        import { useEffect, useState } from "react";
        import { SharedMap } from "fluid-framework";
        import { AzureClient } from "@fluidframework/azure-client";
        import { InsecureTokenProvider } from "@fluidframework/test-client-utils";
    

    Beachten Sie, dass die aus der Fluid Framework-Bibliothek importierten Objekte zum Definieren von Benutzer*innen und Containern erforderlich sind. In den folgenden Schritten werden AzureClient und InsecureTokenProvider zum Konfigurieren des Clientdiensts (siehe TODO 1) verwendet, während SharedMap verwendet wird, um ein zum Erstellen eines Containers erforderliches containerSchema zu konfigurieren (siehe TODO 2).

  2. Fügen Sie die folgenden funktionalen Komponenten und Hilfsfunktionen hinzu:

        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
        }
    

    Beachten Sie, dass AudienceDisplay und AudienceList funktionale Komponenten sind, die das Abrufen und Rendern von Zielgruppendaten übernehmen, während die tryGetAudienceObject-Methode für die Erstellung von Containern und Zielgruppendiensten verantwortlich ist.

Abrufen von Containern und Zielgruppen

Sie können mit einer Hilfsfunktion die Fluid-Daten aus dem Zielgruppenobjekt in die Ansichtsebene (den React-Zustand) abrufen. Die tryGetAudienceObject-Methode wird aufgerufen, wenn die Ansichtskomponente nach dem Auswählen einer Benutzer-ID geladen wird. Der zurückgegebene Wert wird einer React-Zustandseigenschaft zugewiesen.

  1. Ersetzen Sie TODO 1 durch den folgenden Code. Beachten Sie, dass die Werte für userIduserNamecontainerId von der App-Komponente übergeben werden. Wenn kein containerIdContainer vorhanden ist, wird ein neuer Container erstellt. Beachten Sie außerdem, dass der containerId im URL-Hash gespeichert ist. Ein Benutzer oder eine Benutzerin, der bzw. die über einen neuen Browser in eine Sitzung eintritt, kann die URL aus einem vorhandenen Sitzungsbrowser kopieren oder zu localhost:3000 navigieren und die Container-ID manuell eingeben. Bei dieser Implementierung möchten wir den getContainer Aufruf in einen Try Catch einschließen, wenn der Benutzer eine Container-ID eingibt, die nicht vorhanden ist. Weitere Informationen finden Sie in der Containerdokumentation .

        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;
    

Abrufen der Zielgruppe beim Einbinden der Komponente

Nachdem nun definiert wurde, wie die Fluid-Zielgruppe abgerufen wird, muss React angewiesen werden, beim Einbinden der Komponente für die Zielgruppenanzeige tryGetAudienceObject aufzurufen.

  1. Ersetzen Sie TODO 2 durch den folgenden Code. Beachten Sie, dass die Benutzer-ID als user1user2 oder random von der übergeordneten Komponente stammt. Wenn die ID random lautet, wird mit Math.random() eine Zufallszahl als ID generiert. Darüber hinaus wird dem oder der Benutzer*in ein Name basierend auf der ID zugeordnet, wie in userNameList angegeben. Schließlich werden die Zustandsvariablen definiert, in denen die verbundenen Member und der oder die aktuelle Benutzer*in gespeichert werden. In fluidMembers wird eine Liste aller Elemente gespeichert, die mit dem Container verbunden sind, während currentMember das Memberobjekt für den oder die aktuelle*n Benutzer*in bei der Anzeige des Browserkontexts darstellt.

        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();
    
  2. Ersetzen Sie TODO 3 durch den folgenden Code. Hiermit wird tryGetAudienceObject beim Einbinden der Komponente aufgerufen, und die zurückgegebenen Zielgruppenmitglieder werden auf fluidMembers und currentMember festgelegt. Beachten Sie, dass überprüft wird, ob ein Benutzergruppenobjekt zurückgegeben wird, falls ein Benutzer eine containerId eingibt, die nicht vorhanden ist und wir sie zur UserIdSelection-Ansicht zurückgeben müssen (props.onContainerNotFound() behandelt den Wechsel der Ansicht). Es empfiehlt sich außerdem, die Registrierung von Ereignishandlern durch Zurückgeben von audience.off aufzuheben, wenn Bereitstellung der React-Komponente aufgehoben wird.

        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) };
        });
        }, []);
    
  3. Ersetzen Sie TODO 4 durch den folgenden Code. Beachten Sie, dass ein leerer Bildschirm gerendert wird, wenn fluidMembers oder currentMember nicht initialisiert wurde. Die Komponente AudienceList rendert die Memberdaten mit Formatierung (im nächsten Abschnitt implementiert).

        if (!fluidMembers || !currentMember) return (<div/>);
    
        return (
            <AudienceList fluidMembers={fluidMembers} currentMember={currentMember}/>
        )
    

    Hinweis

    Verbindungsübergänge können zu kurzen Zeitfenstern führen, in denen getMyselfundefined zurückgibt. Dies liegt daran, dass die aktuelle Clientverbindung der Zielgruppe noch nicht hinzugefügt wurde, sodass keine übereinstimmende Verbindungs-ID gefunden werden kann. Um React daran zu hindern, eine Seite ohne Zielgruppenmitglieder zu rendern, wird ein Listener hinzugefügt, der updateMembers in membersChanged aufruft. Dies funktioniert, da die Dienstgruppe beim Verbinden des Containers ein membersChanged-Ereignis ausgibt.

Erstellen der Ansicht

  1. Ersetzen Sie TODO 5 durch den folgenden Code. Beachten Sie, dass eine Listenkomponente für jeden Member gerendert wird, der von der Komponente AudienceDisplay übergeben wird. Für jeden Member wird zuerst member.userId mit currentMember.userId verglichen, um zu überprüfen, ob es isSelf für diesen Member zutrifft. Auf diese Weise kann der oder Clientbenutzer*in von den anderen Benutzer*innen unterschieden und die Komponente in einer anderen Farbe angezeigt werden. Anschließend wird die Listenkomponente in ein list-Array gepusht. Jede Komponente zeigt Memberdaten wie userIduserName und additionalDetails an.

        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>
            );
        });
    
  2. Ersetzen Sie TODO 6 durch den folgenden Code. Dadurch werden alle Memberelemente gerendert, die in das list-Array gepusht wurden.

        return (
            <div>
                {list}
            </div>
        );
    

Einrichten der Komponente UserIdSelection

  1. Erstellen Sie die Datei \src\UserIdSelection.js, und öffnen Sie sie im Code-Editor. Diese Komponente enthält Benutzer-ID-Schaltflächen und Eingabefelder für die Container-ID, mit denen Endbenutzer*innen ihre Benutzer-ID und ihre Zusammenarbeitssitzung auswählen können. Fügen Sie die folgenden import-Anweisungen und Funktionskomponenten hinzu:

    import { useState } from 'react';
    
    export const UserIdSelection = (props) => {
        // TODO 1: Define styles and handle user inputs
        return (
        // TODO 2: Return view components
        );
    }
    
  2. Ersetzen Sie TODO 1 durch den folgenden Code. Beachten Sie, dass die onSelectUser-Funktion die Zustandsvariablen in der übergeordneten App-Komponente aktualisiert und eine Ansichtsänderung hervorruft. Die handleSubmit-Methode wird durch Schaltflächenelemente ausgelöst, die in TODO 2 implementiert werden. Außerdem wird mit der handleChange-Methode die Zustandsvariable containerId aktualisiert. Diese Methode wird von einem in TODO 2 implementierten Ereignislistener für Eingabeelemente aufgerufen. Beachten Sie außerdem, dass containerId aktualisiert wird, sodass der Wert aus einem HTML-Element mit der ID containerIdInput (definiert in TODO 2) abgerufen wird.

        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);
        };
    
  3. Ersetzen Sie TODO 2 durch den folgenden Code. Dadurch werden die Schaltflächen für die Benutzer-ID sowie das Eingabefeld für die Container-ID gerendert.

        <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>
    

Starten des Fluid-Servers und Ausführen der Anwendung

Hinweis

In Übereinstimmung mit dem Rest dieser exemplarischen Vorgehensweise wird in diesem Abschnitt ein Fluid-Server mit den Befehlen npx und npm, gestartet. Der Code in diesem Artikel kann jedoch auch für einen Azure Fluid Relay-Server ausgeführt werden. Weitere Informationen finden Sie unter Bereitstellen eines Azure Fluid Relay-Diensts und Herstellen einer Verbindung mit einem Azure Fluid Relay-Dienst.

Führen Sie an der Eingabeaufforderung den folgenden Befehl aus, um den Fluid-Dienst zu starten.

npx @fluidframework/azure-local-service@latest

Öffnen Sie eine neue Eingabeaufforderung, und navigieren Sie zum Stammverzeichnis des Projekts, z. B. C:/My Fluid Projects/fluid-audience-tutorial. Starten Sie den Anwendungsserver mit dem folgenden Befehl. Die Anwendung wird im Browser geöffnet. Dies kann einige Minuten dauern.

npm run start

Navigieren Sie auf einer Browserregisterkarte zu localhost:3000, um die ausgeführte Anwendung anzuzeigen. Um einen neuen Container zu erstellen, wählen Sie eine Benutzer-ID-Schaltfläche aus, und lassen Sie die Container-ID-Eingabe leer. Um einen neuen Benutzer oder eine neue Benutzerin zu simulieren, der bzw. die der Containersitzung beitritt, öffnen Sie eine neue Browserregisterkarte, und navigieren Sie zu localhost:3000. Geben Sie diesmal den Container-ID-Wert ein, den Sie der URL der ersten Browserregisterkarte nach http://localhost:3000/# entnehmen können.

Hinweis

Möglicherweise müssen Sie eine zusätzliche Abhängigkeit installieren, um diese Demo mit Webpack 5 kompatibel zu machen. Wenn Sie einen Kompilierungsfehler im Zusammenhang mit einem Paket des Typs „buffer“ oder „url“ erhalten, führen Sie npm install -D buffer url aus, und versuchen Sie es erneut. Dies wird in einem zukünftigen Release von Fluid Framework behoben.

Nächste Schritte

  • Versuchen Sie, die Demo um weitere Schlüssel-Wert-Paare im Feld additionalDetails in userConfig zu erweitern.
  • Ziehen Sie in Betracht, die Zielgruppe in eine kollaborative Anwendung zu integrieren, die verteilte Datenstrukturen wie SharedMap oder SharedString verwendet.
  • Erfahren Sie mehr über die Zielgruppe.

Tipp

Wenn Sie Änderungen am Code vornehmen, wird das Projekt automatisch neu erstellt, und der Anwendungsserver wird neu geladen. Wenn Sie jedoch Änderungen am Containerschema vornehmen, werden diese erst wirksam, nachdem Sie den Anwendungsserver schließen und neu starten. Setzen Sie dazu den Fokus auf die Eingabeaufforderung, und drücken Sie zweimal STRG-C. Führen Sie npm run start dann erneut aus.