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.
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.
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
Otwórz wiersz polecenia i przejdź do folderu nadrzędnego, w którym chcesz utworzyć projekt; np.
C:\My Fluid Projects
.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
Projekt jest tworzony w podfolderze o nazwie
fluid-audience-tutorial
. Przejdź do niego za pomocą poleceniacd fluid-audience-tutorial
.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
Otwórz plik
\src\App.js
w edytorze kodu. Usuń wszystkie instrukcje domyślneimport
. Następnie usuń wszystkie znaczniki z instrukcjireturn
. 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 ); }
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 (zobaczTODO 2
). WartośćuserId
to identyfikator użytkownika do nawiązania połączenia z kontenerem za pomocą polecenia , acontainerId
wartość to kontener do załadowania. FunkcjehandleSelectUser
ihandleContainerNotFound
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]);
Zastąp ciąg
TODO 2
następującym kodem. Jak wspomniano powyżej, zmiennadisplayAudience
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
Utwórz i otwórz plik
\src\AudienceDisplay.js
w edytorze kodu. Dodaj następujące instrukcjeimport
: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 wymaganegocontainerSchema
do utworzenia kontenera (zobaczTODO 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.
Zastąp ciąg
TODO 1
następującym kodem. Należy pamiętać, że wartości dlauserId
userName
containerId
elementu zostaną przekazane ze składnika App . Jeśli niecontainerId
ma pliku , zostanie utworzony nowy kontener. Należy również pamiętać, że elementcontainerId
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ść dolocalhost: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.
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 jakouser1
user2
lubrandom
. Jeśli identyfikator jestrandom
używanyMath.random()
do generowania losowej liczby jako identyfikatora. Ponadto nazwa zostanie zamapowana na użytkownika na podstawie identyfikatora określonego w plikuuserNameList
. 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, natomiastcurrentMember
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();
Zastąp ciąg
TODO 3
następującym kodem. Spowoduje to wywołanietryGetAudienceObject
elementu, gdy składnik jest zainstalowany i ustawi zwróconych członków grupy odbiorców nafluidMembers
icurrentMember
. 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 poleceniaaudience.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) }; }); }, []);
Zastąp ciąg
TODO 4
następującym kodem. Należy pamiętać, że jeśli elementfluidMembers
lubcurrentMember
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łączeń 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łaniaupdateMembers
metodymembersChanged
. Działa to, ponieważ odbiorcy usługi emitująmembersChanged
zdarzenie, gdy kontener jest połączony.
Tworzenie widoku
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ównujemymember.userId
się z elementem , abycurrentMember.userId
sprawdzić, czy dany element członkowskiisSelf
. 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 tablicylist
. Każdy składnik wyświetli dane składowe, takie jakuserId
userName
iadditionalDetails
.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> ); });
Zastąp ciąg
TODO 6
następującym kodem. Spowoduje to renderowanie wszystkich elementów członkowskich wypchniętych do tablicylist
.return ( <div> {list} </div> );
Konfigurowanie składnika UserIdSelection
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ąceimport
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 ); }
Zastąp ciąg
TODO 1
następującym kodem. Należy pamiętać, żeonSelectUser
funkcja zaktualizuje zmienne stanu w składniku nadrzędnej aplikacji i wyświetli monit o zmianę widoku. MetodahandleSubmit
jest wyzwalana przez elementy przycisku, które zostaną zaimplementowane w plikuTODO 2
.handleChange
Ponadto metoda służy do aktualizowania zmiennejcontainerId
stanu. Ta metoda zostanie wywołana z odbiornika zdarzeń elementu wejściowego zaimplementowanego w programieTODO 2
. Należy również pamiętać, że aktualizujemycontainerId
wartość z elementu HTML o identyfikatorzecontainerIdInput
(zdefiniowanym w plikuTODO 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); };
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 How to: Provision an Azure Fluid Relay service (Instrukcje: aprowizuj usługę Azure Fluid Relay) i How to: Connect to an Azure Fluid Relay service (Jak aprowizować usługę Azure Fluid Relay) i How to: Connect to an Azure Fluid Relay service (Jak nawiązać połączenie z usługą 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:3000
strony . 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
userConfig
plikuadditionalDetails
. - 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ąć Ctrl-C. Następnie uruchom npm run start
ponownie.