操作說明:在流體架構中使用受眾功能
在本教學課程中,您將瞭解如何使用 流體架構 Audience 搭配 React 來建立連線至容器的用戶可視化示範。 物件物件會保存與連線至容器之所有使用者相關的資訊。 在此範例中,Azure 用戶端連結庫將用來建立容器和物件。
下圖顯示標識碼按鈕和容器標識元輸入欄位。 將 [容器標識符] 字段保留空白,然後按兩下 [使用者標識元] 按鈕將會建立新的容器,並以選取的使用者身分加入。 或者,終端使用者可以輸入容器標識碼,並選擇使用者標識碼,將現有的容器加入為選取的使用者。
下一個影像顯示已連線至方塊所代表容器的多個使用者。 以藍色框起的方塊代表正在檢視客戶端的使用者,而以黑色框框的方塊則代表其他連線的使用者。 當新的使用者附加至具有唯一標識符的容器時,方塊數目將會增加。
注意
本教學課程假設您已熟悉 流體架構 概觀,並已完成快速入門。 您也應該熟悉 React 的基本概念、建立 React 專案和 React Hooks。
建立專案
開啟命令提示字元,並流覽至您要在其中建立專案的父資料夾;例如,
C:\My Fluid Projects
。在提示字元中執行下列命令。 (請注意,CLI 是 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
定義與 Fluid 服務伺服器的連線,並定義 Fluid 容器的起始架構。 @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
值是要載入的容器。 和handleContainerNotFound
函handleSelectUser
式會以回呼的形式傳入兩個檢視,並管理狀態轉換。handleSelectUser
嘗試建立/載入容器時呼叫 。handleContainerNotFound
在建立/載入容器失敗時呼叫 。請注意,userId 和 containerId 值會透過
handleSelectUser
函式來自 UserIdSelection 元件。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
變數會判斷我們是否轉譯 AudienceDisplay 元件或 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";
請注意,定義使用者和容器時,需要從 流體架構 連結庫匯入的物件。 在下列步驟中,AzureClient 和 InsecureTokenProvider 將用來設定用戶端服務(請參閱
TODO 1
),而 SharedMap 將用來containerSchema
設定建立容器所需的 (請參閱TODO 2
)。新增下列功能元件和協助程式函式:
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 }
請注意, AudienceDisplay 和 AudienceList 是處理取得和轉譯對象數據的功能元件,而
tryGetAudienceObject
方法會處理容器和物件服務的建立。
取得容器和物件
您可以使用協助程式函式,從 Audience 物件取得 Fluid 數據到檢視層(React 狀態)。 tryGetAudienceObject
選取使用者標識碼之後,檢視元件載入時會呼叫 方法。 傳回的值會指派給 React 狀態屬性。
以下列程式碼取代
TODO 1
。 請注意,的值userId
userName
containerId
將會從 應用程式 元件傳入。containerId
如果沒有 ,則會建立新的容器。 此外,請注意 ,containerId
會儲存在URL哈希上。 從新瀏覽器輸入會話的使用者,可以從現有的會話瀏覽器複製 URL,或流覽至localhost:3000
並手動輸入容器標識碼。 在此實作中,我們想要在使用者輸入不存在的容器標識符的情況下,將呼叫包裝getContainer
在 try catch 中。 如需詳細資訊, 請流覽容器 檔。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
。 請注意,使用者標識碼會以 或random
的形式user1
user2
來自父元件。 如果標識碼是random
用來Math.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
。 請注意,我們會檢查物件是否在使用者輸入不存在的 containerId 時傳回物件,而我們需要將它們傳回 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}/> )
注意
線上轉換可能會導致短時間範圍,其中會
undefined
傳getMyself
回 。 這是因為目前的用戶端連線尚未新增至物件,因此找不到相符的連接標識碼。 為了防止 React 轉譯沒有對象成員的頁面,我們會新增接聽程式以在 上membersChanged
呼叫updateMembers
。 這可運作,因為服務物件會在membersChanged
連線容器時發出事件。
建立檢視表
以下列程式碼取代
TODO 5
。 請注意,我們會針對從 AudienceDisplay 元件傳遞的每個成員轉譯清單元件。 對於每個成員,我們會先比較member.userId
,currentMember.userId
以檢查該成員isSelf
是否為 。 如此一來,我們可以區分用戶端使用者與其他使用者,並以不同的色彩顯示元件。 接著,我們會將清單元件推送至list
數組。 每個元件都會顯示 成員資料,例如userId
userName
和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
,從具有標識符containerIdInput
的 HTML 元素取得值(定義於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>
啟動 Fluid 伺服器並執行應用程式
注意
為了符合本操作說明的其餘部分,本節會使用 npx
和 npm
命令來啟動 Fluid 伺服器。 不過,本文中的程式代碼也可以針對 Azure Fluid Relay 伺服器執行。 如需詳細資訊,請參閱如何:布建 Azure Fluid Relay 服務和如何:連線至 Azure Fluid Relay 服務
在命令提示字元中,執行下列命令以啟動 Fluid 服務。
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 相容。 如果您收到與「緩衝區」或「URL」套件相關的編譯錯誤,請執行 npm install -D buffer url
並再試一次。 這會在未來的 流體架構 版本中解決。
下一步
- 請嘗試在的
userConfig
欄位中擴充具有更多索引鍵/值組的additionalDetails
示範。 - 請考慮將物件整合到共同作業應用程式,以利用 SharedMap 或 SharedString 等分散式數據結構。
- 深入了解 物件。
提示
當您變更程式代碼時,專案會自動重建,而應用程式伺服器將會重載。 不過,如果您變更容器架構,只有在關閉並重新啟動應用程式伺服器時,它們才會生效。 若要這樣做,請將焦點放在命令提示字元,然後按 Ctrl-C 兩次。 然後再次執行 npm run start
。