如何:在 流體架構 中使用物件功能

在本教學課程中,您將瞭解如何使用 流體架構 Audience 搭配 React 來建立連線至容器的用戶可視化示範。 物件物件會保存與連線至容器之所有使用者相關的資訊。 在此範例中,Azure 用戶端連結庫將用來建立容器和物件。

下圖顯示標識碼按鈕和容器標識元輸入欄位。 將 [容器標識符] 字段保留空白,然後按兩下 [使用者標識元] 按鈕將會建立新的容器,並以選取的使用者身分加入。 或者,終端使用者可以輸入容器標識碼,並選擇使用者標識碼,將現有的容器加入為選取的使用者。

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

下一個影像顯示已連線至方塊所代表容器的多個使用者。 以藍色框起的方塊代表正在檢視客戶端的使用者,而以黑色框框的方塊則代表其他連線的使用者。 當新的使用者附加至具有唯一標識符的容器時,方塊數目將會增加。

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

注意

本教學課程假設您已熟悉 流體架構 概觀,並已完成快速入門。 您也應該熟悉 React 的基本概念建立 React 專案和 React Hooks

建立專案

  1. 開啟命令提示字元,並流覽至您要在其中建立專案的父資料夾;例如, C:\My Fluid Projects

  2. 在提示字元中執行下列命令。 (請注意,CLI 是 npx,而不是 npm。安裝Node.js時已安裝。

    npx create-react-app fluid-audience-tutorial
    
  3. 專案會在名為 fluid-audience-tutorial的子資料夾中建立。 使用 命令 cd fluid-audience-tutorial流覽至它。

  4. 專案使用下列 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
    

撰寫項目程序代碼

設定狀態變數和元件檢視

  1. 在程式代碼編輯器中開啟檔案 \src\App.js 。 刪除所有預設 import 語句。 然後,從 return 語句中刪除所有標記。 然後新增元件的匯入語句和 React 攔截。 請注意,我們將在後續步驟中實作匯入 的 AudienceDisplayUserIdSelection 元件。 檔案看起來應該如下所示:

        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. 以下列程式碼取代 TODO 1。 此程式代碼會初始化將用於應用程式內的本機狀態變數。 值 displayAudience 會判斷我們是否轉譯 AudienceDisplay 元件或 UserIdSelection 元件(請參閱 TODO 2)。 值 userId 是用來連接到容器的使用者標識碼,而 containerId 值是要載入的容器。 和 handleContainerNotFoundhandleSelectUser式會以回呼的形式傳入兩個檢視,並管理狀態轉換。 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]);
    
  3. 以下列程式碼取代 TODO 2。 如上所述, displayAudience 變數會判斷我們是否轉譯 AudienceDisplay 元件或 UserIdSelection 元件。 此外,更新狀態變數的函式會當做屬性傳遞至元件。

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

設定 AudienceDisplay 元件

  1. 在程式代碼編輯器中建立並開啟檔案 \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)。

  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
        }
    

    請注意, AudienceDisplayAudienceList 是處理取得和轉譯對象數據的功能元件,而 tryGetAudienceObject 方法會處理容器和物件服務的建立。

取得容器和物件

您可以使用協助程式函式,從 Audience 物件取得 Fluid 數據到檢視層(React 狀態)。 tryGetAudienceObject選取使用者標識碼之後,檢視元件載入時會呼叫 方法。 傳回的值會指派給 React 狀態屬性。

  1. 以下列程式碼取代 TODO 1。 請注意,的值 userIduserNamecontainerId 將會從 應用程式 元件傳入。 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

  1. 以下列程式碼取代 TODO 2。 請注意,使用者標識碼會以 或 random的形式user1user2來自父元件。 如果標識碼是 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();
    
  2. 以下列程式碼取代 TODO 3。 這會在掛接元件時呼叫 tryGetAudienceObject ,並將傳回的物件成員設定為 fluidMemberscurrentMember。 請注意,我們會檢查物件是否在使用者輸入不存在的 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) };
        });
        }, []);
    
  3. 以下列程式碼取代 TODO 4。 請注意,如果 fluidMemberscurrentMember 尚未初始化,則會轉譯空白畫面。 AudienceList 元件會以樣式呈現成員數據(將在下一節中實作)。

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

    注意

    連線 轉換可能會導致傳回undefined的短時間時段getMyself。 這是因為目前的用戶端連線尚未新增至物件,因此找不到相符的連接標識碼。 為了防止 React 轉譯沒有對象成員的頁面,我們會新增接聽程式以在 上membersChanged呼叫 updateMembers 。 這可運作,因為服務物件會在 membersChanged 連線容器時發出事件。

建立檢視表

  1. 以下列程式碼取代 TODO 5。 請注意,我們會針對從 AudienceDisplay 元件傳遞的每個成員轉譯清單元件。 對於每個成員,我們會先比較 member.userIdcurrentMember.userId 以檢查該成員 isSelf是否為 。 如此一來,我們可以區分用戶端使用者與其他使用者,並以不同的色彩顯示元件。 接著,我們會將清單元件推送至 list 數組。 每個元件都會顯示 成員資料,例如 userIduserNameadditionalDetails

        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. 以下列程式碼取代 TODO 6。 這會轉譯我們推送至 list 陣列的所有成員專案。

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

設定 UserIdSelection 元件

  1. 在程式代碼編輯器中建立並開啟檔案 \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
        );
    }
    
  2. 以下列程式碼取代 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);
        };
    
  3. 以下列程式碼取代 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 伺服器並執行應用程式

注意

為了符合本操作說明的其餘部分,本節會使用 npxnpm 命令來啟動 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