Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом руководстве описано, как использовать аудиторию Fluid Framework с React, чтобы создать визуальную демонстрацию пользователей, подключающихся к контейнеру. Объект аудитории содержит сведения, связанные со всеми пользователями, подключенными к контейнеру. В этом примере клиентская библиотека Azure будет использоваться для создания контейнера и аудитории.
На следующем рисунке показаны кнопки идентификатора и поле ввода идентификатора контейнера. Оставив поле идентификатора контейнера пустым и нажав кнопку идентификатора пользователя, создадит новый контейнер и присоединится к выбранному пользователю. Кроме того, конечный пользователь может ввести идентификатор контейнера и выбрать идентификатор пользователя для присоединения существующего контейнера в качестве выбранного пользователя.
На следующем рисунке показано несколько пользователей, подключенных к контейнеру, представленному полями. Поле, очерченное синим цветом, представляет пользователя, который просматривает клиент, а поля, описанные в черном цвете, представляют других подключенных пользователей. При подключении новых пользователей к контейнеру с уникальным идентификатором число полей увеличится.
Примечание.
В этом руководстве предполагается, что вы знакомы с обзором Fluid Framework и завершили краткое руководство. Вы также должны ознакомиться с основами React, созданием проектов React и React Hooks.
Создание проекта
Откройте командную строку и перейдите в родительскую папку, в которой вы хотите создать проект; например,
C:\My Fluid Projects.Выполните следующую команду в командной строке. (Обратите внимание, что интерфейс командной строки npx, а не npm. Он был установлен при установке Node.js.)
npx create-react-app fluid-audience-tutorialПроект создается в подпапке с именем
fluid-audience-tutorial. Перейдите к нему с помощью командыcd fluid-audience-tutorial.В проекте используются следующие библиотеки Fluid:
Библиотека Описание fluid-frameworkСодержит распределенную структуру данных SharedMap, которая синхронизирует данные между клиентами. @fluidframework/azure-clientОпределяет подключение к серверу службы "Жидкость" и определяет начальную схему для контейнера "Жидкость". @fluidframework/test-client-utilsОпределяет insecureTokenProvider , необходимый для создания подключения к текучим службам. Выполните следующую команду, чтобы установить библиотеки.
npm install @fluidframework/azure-client @fluidframework/test-client-utils fluid-framework
Код проекта
Настройка переменных состояния и представления компонентов
Откройте файл
\src\App.jsв редакторе кода. Удалите все инструкции по умолчаниюimport. Затем удалите все разметку из инструкцииreturn. Затем добавьте инструкции импорта для компонентов и перехватчиков React. Обратите внимание, что мы реализуем импортированные компоненты AudienceDisplay и UserIdSelection в последующих шагах. Файл должен выглядеть примерно так: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 ); }Замените
TODO 1следующим кодом. Этот код инициализирует переменные локального состояния, которые будут использоваться в приложении. ЗначениеdisplayAudienceопределяет, отображается ли компонент AudienceDisplay или компонент UserIdSelection (см. ).TODO 2ЗначениемuserIdявляется идентификатор пользователя для подключения к контейнеру иcontainerIdзначением является контейнер для загрузки.handleSelectUserФункцииhandleContainerNotFoundпередаются как обратные вызовы двум представлениям и управляют переходами состояния.handleSelectUserвызывается при попытке создать или загрузить контейнер.handleContainerNotFoundвызывается при сбое создания или загрузки контейнера.Обратите внимание, что значения userId и containerId будут поступать из компонента UserIdSelection через функцию
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]);Замените
TODO 2следующим кодом. Как указано выше, переменная определяет, отрисовываетсяdisplayAudienceили компонент UserIdSelection. Кроме того, функции для обновления переменных состояния передаются в компоненты в качестве свойств.(displayAudience) ? <AudienceDisplay userId={userId} containerId={containerId} onContainerNotFound={handleContainerNotFound}/> : <UserIdSelection onSelectUser={handleSelectUser}/>
Настройка компонента AudienceDisplay
Создайте и откройте файл
\src\AudienceDisplay.jsв редакторе кода. Добавьте следующие операторыimport:import { useEffect, useState } from "react"; import { SharedMap } from "fluid-framework"; import { AzureClient } from "@fluidframework/azure-client"; import { InsecureTokenProvider } from "@fluidframework/test-client-utils";Обратите внимание, что для определения пользователей и контейнеров требуются объекты, импортированные из библиотеки Fluid Framework. В следующих шагах AzureClient и InsecureTokenProvider
Добавьте следующие функциональные компоненты и вспомогательные функции:
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 }Обратите внимание, что АудиторияDisplay и AudienceList являются функциональными компонентами, которые обрабатывают получение и отрисовку данных аудитории, а метод
tryGetAudienceObjectобрабатывает создание служб контейнера и аудитории.
Получение контейнера и аудитории
Вы можете использовать вспомогательная функция для получения данных "Жидкость" из объекта Аудитории в слой представления (состояние React). Метод tryGetAudienceObject вызывается, когда компонент представления загружается после выбора идентификатора пользователя. Возвращаемое значение присваивается свойству состояния React.
Замените
TODO 1следующим кодом. Обратите внимание, что значения, которыеuserIduserNamecontainerIdбудут переданы из компонента приложения. Если нетcontainerId, создается новый контейнер. Кроме того, обратите внимание, чтоcontainerIdон хранится в хэше URL-адреса. Пользователь, входящий в сеанс из нового браузера, может скопировать URL-адрес из существующего браузера сеансов или перейти иlocalhost:3000вручную ввести идентификатор контейнера. С помощью этой реализации мы хотим упаковатьgetContainerвызов в попытку перехвата в случае, если пользователь вводит идентификатор контейнера, который не существует. Дополнительные сведения см. в документации по контейнерам.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;
Получение аудитории при подключении компонентов
Теперь, когда мы определили, как получить аудиторию Fluid, необходимо сообщить React, чтобы вызвать tryGetAudienceObject , когда компонент отображения аудитории подключен.
Замените
TODO 2следующим кодом. Обратите внимание, что идентификатор пользователя будет поступать из родительского компонента какuser1user2илиrandom. Если идентификатор используетсяrandomMath.random()для создания случайного числа в качестве идентификатора. Кроме того, имя будет сопоставлено пользователю на основе его идентификатора, как указано вuserNameList. Наконец, мы определяем переменные состояния, которые будут хранить подключенные элементы, а также текущего пользователя.fluidMembersбудет хранить список всех элементов, подключенных к контейнеру, в то время какcurrentMemberбудет содержать объект-член, представляющий текущего пользователя, просматривающего контекст браузера.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();Замените
TODO 3следующим кодом. При этом компонент будет вызыватьсяtryGetAudienceObject, когда компонент подключен и заданы возвращаемые участникиfluidMembersаудитории.currentMemberОбратите внимание, что мы проверяем, возвращается ли объект аудитории, если пользователь вводит идентификатор контейнера, который не существует, и нам нужно вернуть их в представление UserIdSelection (props.onContainerNotFound()будет обрабатывать переключение представления). Кроме того, рекомендуется отменять регистрацию обработчиков событий при отключении компонента React, возвращая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) }; }); }, []);Замените
TODO 4следующим кодом. Обратите внимание, что еслиfluidMembersилиcurrentMemberон не инициализирован, отрисовывается пустой экран. Компонент AudienceList отрисовывает данные-члены с стили (для реализации в следующем разделе).if (!fluidMembers || !currentMember) return (<div/>); return ( <AudienceList fluidMembers={fluidMembers} currentMember={currentMember}/> )Примечание.
Переходы подключений могут привести к коротким периодам времени, в которых
getMyselfвозвращается.undefinedЭто связано с тем, что текущее подключение клиента еще не было добавлено в аудиторию, поэтому не удается найти соответствующий идентификатор подключения. Чтобы предотвратить отрисовку страницы Без участников аудитории, мы добавим прослушиватель для вызоваupdateMembersmembersChanged. Это работает, так как аудитория службы выдаетmembersChangedсобытие при подключении контейнера.
Создание представления
Замените
TODO 5следующим кодом. Обратите внимание, что мы отрисовываем компонент списка для каждого члена, переданного из компонента AudienceDisplay . Для каждого элемента сначала сравниваемmember.userIdcurrentMember.userId, чтобы проверить, является ли этот элементisSelf. Таким образом, мы можем отличить пользователя клиента от других пользователей и отобразить компонент с другим цветом. Затем мы принудим компонент списка к массивуlist. Каждый компонент будет отображать данные-члены, такие какuserIduserNameи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> ); });Замените
TODO 6следующим кодом. При этом будут отображены все элементы-члены, отправленные вlistмассив.return ( <div> {list} </div> );
Настройка компонента UserIdSelection
Создайте и откройте файл
\src\UserIdSelection.jsв редакторе кода. Этот компонент будет включать кнопки идентификатора пользователя и поля ввода идентификатора контейнера, которые позволяют конечным пользователям выбирать идентификатор пользователя и сеанс совместной работы. Добавьте следующиеimportинструкции и функциональные компоненты:import { useState } from 'react'; export const UserIdSelection = (props) => { // TODO 1: Define styles and handle user inputs return ( // TODO 2: Return view components ); }Замените
TODO 1следующим кодом. Обратите внимание, чтоonSelectUserфункция обновит переменные состояния в родительском компоненте приложения и предложит изменить представление. МетодhandleSubmitактивируется элементами кнопки, которые будут реализованы вTODO 2. Кроме того,handleChangeметод используется для обновления переменнойcontainerIdсостояния. Этот метод будет вызываться из прослушивателя событий входного элемента, реализованного вTODO 2. Кроме того, обратите внимание, что мы обновляемcontainerIdзначение из HTML-элемента с идентификаторомcontainerIdInput(определенным в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); };Замените
TODO 2следующим кодом. Это приведет к отображению кнопок идентификатора пользователя, а также поля ввода идентификатора контейнера.<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>
Запустите сервер "Жидкость" и запустите приложение
Примечание.
Чтобы соответствовать остальной части этого руководства, в этом разделе используются npx и npm команды для запуска сервера Fluid. Однако код, приведенный в этой статье, также может выполняться на сервере Ретранслятора Azure Fluid Relay. Дополнительные сведения см. в статье "Практическое руководство. Подготовка службы Azure Fluid Relay и практическое руководство. Подключение к службе Ретранслятора Жидкости Azure"
В командной строке выполните следующую команду, чтобы запустить службу "Жидкость".
npx @fluidframework/azure-local-service@latest
Откройте новую командную строку и перейдите в корневой каталог проекта; например, C:/My Fluid Projects/fluid-audience-tutorial. Запустите сервер приложений с помощью следующей команды. Приложение откроется в браузере. Это может занять несколько минут.
npm run start
Перейдите на localhost:3000 вкладку браузера, чтобы просмотреть работающее приложение. Чтобы создать контейнер, нажмите кнопку идентификатора пользователя, оставив поле ввода идентификатора контейнера пустым. Чтобы имитировать нового пользователя, присоединенного к сеансу контейнера, откройте новую вкладку браузера и перейдите к ней localhost:3000. На этот раз введите значение идентификатора контейнера, которое можно найти в url-адресе http://localhost:3000/#первой вкладки браузера.
Примечание.
Возможно, потребуется установить дополнительную зависимость, чтобы сделать эту демонстрацию совместимой с webpack 5. Если вы получаете ошибку компиляции, связанную с пакетом "buffer" или "url", выполните npm install -D buffer url и повторите попытку. Это будет решено в будущем выпуске Fluid Framework.
Следующие шаги
- Попробуйте расширить демонстрацию с дополнительными парами "ключ-значение" в
additionalDetailsполеuserConfig. - Рассмотрите возможность интеграции аудитории в приложение для совместной работы, которое использует распределенные структуры данных, такие как SharedMap или SharedString.
- Узнайте больше о аудитории.
Совет
При внесении изменений в код проект автоматически перестроится, а сервер приложений перезагрузит. Однако при внесении изменений в схему контейнера они вступают в силу только при закрытии и перезапуске сервера приложений. Для этого наведите фокус на командную строку и дважды нажмите клавиши CTRL-C. Затем снова запустите.npm run start