Instrukcje: używanie funkcji odbiorców w Elastyczna struktura

W tym samouczku dowiesz się, jak używać grupy odbiorców Elastyczna struktura z platformą React w celu utworzenia wizualnego pokazu użytkowników łączących się z kontenerem. Obiekt odbiorców zawiera informacje dotyczące wszystkich użytkowników połączonych z kontenerem. W tym przykładzie biblioteka klienta platformy Azure zostanie użyta do utworzenia kontenera i odbiorców.

Na poniższej ilustracji przedstawiono przyciski identyfikatorów i pole wejściowe identyfikatora kontenera. Pozostawienie pustego pola identyfikatora kontenera i kliknięcie przycisku identyfikatora użytkownika spowoduje utworzenie nowego kontenera i dołączenie jako wybranego użytkownika. Alternatywnie użytkownik końcowy może wprowadzić identyfikator kontenera i wybrać identyfikator użytkownika, aby dołączyć do istniejącego kontenera jako wybranego użytkownika.

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

Następny obraz przedstawia wielu użytkowników połączonych z kontenerem reprezentowanym przez pola. Pole opisane na niebiesko reprezentuje użytkownika, który wyświetla klienta, podczas gdy pola opisane w kolorze czarnym reprezentują innych połączonych użytkowników. Gdy nowi użytkownicy dołączają do kontenera z unikatowym identyfikatorem, liczba pól wzrośnie.

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

Uwaga

W tym samouczku założono, że znasz Elastyczna struktura Przegląd i że ukończono przewodnik Szybki start. Należy również zapoznać się z podstawami platformy React, tworzeniem projektów React i platformą React Hooks.

Tworzenie projektu

  1. Otwórz wiersz polecenia i przejdź do folderu nadrzędnego, w którym chcesz utworzyć projekt; np. C:\My Fluid Projects.

  2. Uruchom następujące polecenie w wierszu polecenia. (Należy pamiętać, że interfejs wiersza polecenia to npx, a nie npm. Został on zainstalowany podczas instalowania Node.js).

    npx create-react-app fluid-audience-tutorial
    
  3. Projekt jest tworzony w podfolderze o nazwie fluid-audience-tutorial. Przejdź do niego za pomocą polecenia cd fluid-audience-tutorial.

  4. W projekcie są używane następujące biblioteki płynów:

    Biblioteka opis
    fluid-framework Zawiera rozproszoną strukturę danych SharedMap, która synchronizuje dane między klientami.
    @fluidframework/azure-client Definiuje połączenie z serwerem usługi fluida i definiuje schemat początkowy dla kontenera Fluid.
    @fluidframework/test-client-utils Definiuje element InsecureTokenProvider potrzebny do utworzenia połączenia z usługą fluida.

    Uruchom następujące polecenie, aby zainstalować biblioteki.

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

Kod projektu

Konfigurowanie zmiennych stanu i widoku składników

  1. Otwórz plik \src\App.js w edytorze kodu. Usuń wszystkie instrukcje domyślne import . Następnie usuń wszystkie znaczniki z instrukcji return . Następnie dodaj instrukcje importu dla składników i punktów zaczepienia platformy React. Pamiętaj, że w kolejnych krokach zostaną zaimplementowane zaimportowane składniki AudienceDisplay i UserIdSelection . Plik powinien wyglądać następująco:

        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. Zastąp ciąg TODO 1 następującym kodem. Ten kod inicjuje zmienne stanu lokalnego, które będą używane w aplikacji. Wartość displayAudience określa, czy renderujemy składnik AudienceDisplay lub składnik UserIdSelection (zobacz TODO 2). Wartość userId to identyfikator użytkownika do nawiązania połączenia z kontenerem za pomocą polecenia , a containerId wartość to kontener do załadowania. Funkcje handleSelectUser i handleContainerNotFound są przekazywane jako wywołania zwrotne do dwóch widoków i zarządzania przejściami stanu. handleSelectUser Metoda jest wywoływana podczas próby utworzenia/załadowania kontenera. handleContainerNotFound Jest wywoływany podczas tworzenia/ładowania kontenera kończy się niepowodzeniem.

    Należy pamiętać, że wartości userId i containerId będą pochodzić ze składnika UserIdSelection za pośrednictwem handleSelectUser funkcji.

        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. Zastąp ciąg TODO 2 następującym kodem. Jak wspomniano powyżej, zmienna displayAudience określi, czy renderujemy składnik AudienceDisplay lub składnik UserIdSelection . Ponadto funkcje do aktualizowania zmiennych stanu są przekazywane do składników jako właściwości.

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

Konfigurowanie składnika AudienceDisplay

  1. Utwórz i otwórz plik \src\AudienceDisplay.js w edytorze kodu. Dodaj następujące instrukcje import:

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

    Należy pamiętać, że obiekty zaimportowane z biblioteki Elastyczna struktura są wymagane do definiowania użytkowników i kontenerów. W poniższych krokach usługa AzureClient i InsecureTokenProvider zostaną użyte do skonfigurowania usługi klienta (zobacz TODO 1), a obiekt SharedMap zostanie użyty do skonfigurowania wymaganego containerSchema do utworzenia kontenera (zobacz TODO 2).

  2. Dodaj następujące składniki funkcjonalne i funkcje pomocnicze:

        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
        }
    

    Należy pamiętać, że grupy AudienceDisplay i AudienceList są składnikami funkcjonalnymi, które obsługują pobieranie i renderowanie danych odbiorców, podczas gdy tryGetAudienceObject metoda obsługuje tworzenie kontenerów i usług odbiorców.

Pobieranie kontenera i odbiorców

Możesz użyć funkcji pomocniczej, aby pobrać dane płynu z obiektu Audience do warstwy widoku (stan React). Metoda jest wywoływana tryGetAudienceObject , gdy składnik widoku jest ładowany po wybraniu identyfikatora użytkownika. Zwrócona wartość jest przypisywana do właściwości stanu react.

  1. Zastąp ciąg TODO 1 następującym kodem. Należy pamiętać, że wartości dla userIduserNamecontainerId elementu zostaną przekazane ze składnika App . Jeśli nie containerIdma pliku , zostanie utworzony nowy kontener. Należy również pamiętać, że element containerId jest przechowywany na skrótzie adresu URL. Użytkownik wprowadzający sesję z nowej przeglądarki może skopiować adres URL z istniejącej przeglądarki sesji lub przejść do localhost:3000 i ręcznie wprowadzić identyfikator kontenera. Dzięki tej implementacji chcemy opakowować getContainer wywołanie w metodzie try catch w przypadku, gdy użytkownik wprowadzi identyfikator kontenera, który nie istnieje. Więcej informacji można znaleźć w dokumentacji kontenerów .

        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;
    

Pobieranie odbiorców podczas instalacji składnika

Teraz, gdy zdefiniowaliśmy sposób uzyskiwania odbiorców płynu, musimy poinformować platformę React o wywołaniu tryGetAudienceObject po zamontowaniu składnika Odbiorcy wyświetlania.

  1. Zastąp ciąg TODO 2 następującym kodem. Należy pamiętać, że identyfikator użytkownika będzie pochodzić ze składnika nadrzędnego jako user1user2 lub random. Jeśli identyfikator jest random używany Math.random() do generowania losowej liczby jako identyfikatora. Ponadto nazwa zostanie zamapowana na użytkownika na podstawie identyfikatora określonego w pliku userNameList. Na koniec definiujemy zmienne stanu, które będą przechowywać połączone elementy członkowskie, a także bieżącego użytkownika. fluidMembers Program będzie przechowywać listę wszystkich elementów członkowskich połączonych z kontenerem, natomiast currentMember będzie zawierać obiekt członkowski reprezentujący bieżący użytkownik wyświetlający kontekst przeglądarki.

        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. Zastąp ciąg TODO 3 następującym kodem. Spowoduje to wywołanie tryGetAudienceObject elementu, gdy składnik jest zainstalowany i ustawi zwróconych członków grupy odbiorców na fluidMembers i currentMember. Należy pamiętać, że sprawdzamy, czy obiekt odbiorców jest zwracany w przypadku, gdy użytkownik wprowadzi identyfikator containerId, który nie istnieje, i musimy zwrócić go do widoku UserIdSelection (props.onContainerNotFound() będzie obsługiwać przełączanie widoku). Warto również wyrejestrować programy obsługi zdarzeń po odinstalowaniu składnika React przez zwrócenie polecenia audience.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) };
        });
        }, []);
    
  3. Zastąp ciąg TODO 4 następującym kodem. Należy pamiętać, że jeśli element fluidMembers lub currentMember nie został zainicjowany, jest renderowany pusty ekran. Składnik AudienceList renderuje dane składowe ze stylem (które mają zostać zaimplementowane w następnej sekcji).

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

    Uwaga

    przejścia Połączenie ion mogą spowodować krótkie okna chronometrażu, w których getMyself zwraca wartość undefined. Dzieje się tak, ponieważ bieżące połączenie klienta nie zostało jeszcze dodane do odbiorców, więc nie można odnaleźć zgodnego identyfikatora połączenia. Aby zapobiec renderowaniu strony przez platformę React bez członków grupy odbiorców, dodamy odbiornik do wywołania updateMembers metody membersChanged. Działa to, ponieważ odbiorcy usługi emitują membersChanged zdarzenie, gdy kontener jest połączony.

Tworzenie widoku

  1. Zastąp ciąg TODO 5 następującym kodem. Zwróć uwagę, że renderujemy składnik listy dla każdego elementu członkowskiego przekazanego ze składnika AudienceDisplay . Dla każdego elementu członkowskiego najpierw porównujemy member.userId się z elementem , aby currentMember.userId sprawdzić, czy dany element członkowski isSelf. Dzięki temu możemy odróżnić użytkownika klienta od innych użytkowników i wyświetlić składnik za pomocą innego koloru. Następnie wypchniemy składnik listy do tablicy list . Każdy składnik wyświetli dane składowe, takie jak userIduserName i additionalDetails.

        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. Zastąp ciąg TODO 6 następującym kodem. Spowoduje to renderowanie wszystkich elementów członkowskich wypchniętych do tablicy list .

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

Konfigurowanie składnika UserIdSelection

  1. Utwórz i otwórz plik \src\UserIdSelection.js w edytorze kodu. Ten składnik będzie zawierać przyciski identyfikatora użytkownika i pola wejściowe identyfikatora kontenera, które umożliwiają użytkownikom końcowym wybranie identyfikatora użytkownika i sesji współpracy. Dodaj następujące import instrukcje i składniki funkcjonalne:

    import { useState } from 'react';
    
    export const UserIdSelection = (props) => {
        // TODO 1: Define styles and handle user inputs
        return (
        // TODO 2: Return view components
        );
    }
    
  2. Zastąp ciąg TODO 1 następującym kodem. Należy pamiętać, że onSelectUser funkcja zaktualizuje zmienne stanu w składniku nadrzędnej aplikacji i wyświetli monit o zmianę widoku. Metoda handleSubmit jest wyzwalana przez elementy przycisku, które zostaną zaimplementowane w pliku TODO 2. handleChange Ponadto metoda służy do aktualizowania zmiennej containerId stanu. Ta metoda zostanie wywołana z odbiornika zdarzeń elementu wejściowego zaimplementowanego w programie TODO 2. Należy również pamiętać, że aktualizujemy containerId wartość z elementu HTML o identyfikatorze containerIdInput (zdefiniowanym w pliku TODO 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);
        };
    
  3. Zastąp ciąg TODO 2 następującym kodem. Spowoduje to renderowanie przycisków identyfikatora użytkownika oraz pola wejściowego identyfikatora kontenera.

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

Uruchamianie serwera fluida i uruchamianie aplikacji

Uwaga

Aby dopasować pozostałe instrukcje, w tej sekcji użyto npx poleceń i npm , aby uruchomić serwer fluidu. Jednak kod w tym artykule może być również uruchamiany na serwerze usługi Azure Fluid Relay. Aby uzyskać więcej informacji, zobacz Jak aprowizować usługę Azure Fluid Relay i Instrukcje: Połączenie do usługi Azure Fluid Relay

W wierszu polecenia uruchom następujące polecenie, aby uruchomić usługę Fluid.

npx @fluidframework/azure-local-service@latest

Otwórz nowy wiersz polecenia i przejdź do katalogu głównego projektu; na przykład C:/My Fluid Projects/fluid-audience-tutorial. Uruchom serwer aplikacji za pomocą następującego polecenia. Aplikacja zostanie otwarta w przeglądarce. Może to potrwać kilka minut.

npm run start

Przejdź do localhost:3000 karty przeglądarki, aby wyświetlić uruchomioną aplikację. Aby utworzyć nowy kontener, wybierz przycisk identyfikatora użytkownika, pozostawiając puste dane wejściowe identyfikatora kontenera. Aby zasymulować nowego użytkownika przyłączonego do sesji kontenera, otwórz nową kartę przeglądarki i przejdź do localhost:3000strony . Tym razem wprowadź wartość identyfikatora kontenera, która można znaleźć w sekcji http://localhost:3000/#adres URL pierwszej karty przeglądarki.

Uwaga

Może być konieczne zainstalowanie dodatkowej zależności, aby ta demonstracja mogła być zgodna z pakietem Webpack 5. Jeśli wystąpi błąd kompilacji związany z pakietem "buffer" lub "url", uruchom polecenie npm install -D buffer url i spróbuj ponownie. Zostanie to rozwiązane w przyszłej wersji Elastyczna struktura.

Następne kroki

  • Spróbuj rozszerzyć pokaz przy użyciu większej liczby par klucz/wartość w polu w userConfigpliku additionalDetails .
  • Rozważ zintegrowanie odbiorców z aplikacją do współpracy, która korzysta z rozproszonych struktur danych, takich jak SharedMap lub SharedString.
  • Dowiedz się więcej o odbiorcach.

Napiwek

Po wprowadzeniu zmian w kodzie projekt zostanie automatycznie ponownie skompiluje i ponownie załaduje serwer aplikacji. Jeśli jednak wprowadzisz zmiany w schemacie kontenera, zostaną one zastosowane tylko po zamknięciu i ponownym uruchomieniu serwera aplikacji. W tym celu należy skupić się na wierszu polecenia i dwukrotnie nacisnąć klawisze Ctrl-C. Następnie uruchom npm run start ponownie.