Partilhar via


Como: Usar recursos de público no Fluid Framework

Neste tutorial, você aprenderá sobre como usar o Fluid Framework Audience com o React para criar uma demonstração visual dos usuários que se conectam a um contêiner. O objeto audience contém informações relacionadas a todos os usuários conectados ao contêiner. Neste exemplo, a biblioteca do Cliente do Azure será usada para criar o contêiner e a audiência.

A imagem a seguir mostra botões de ID e um campo de entrada de ID de contêiner. Deixar o campo ID do contêiner em branco e clicar em um botão de ID do usuário criará um novo contêiner e ingressará como o usuário selecionado. Como alternativa, o usuário final pode inserir um ID de contêiner e escolher um ID de usuário para ingressar em um contêiner existente como o usuário selecionado.

Uma captura de tela de um navegador com botões para selecionar um usuário.

A próxima imagem mostra vários usuários conectados a um contêiner representado por caixas. A caixa delineada em azul representa o usuário que está visualizando o cliente, enquanto as caixas delineadas em preto representam os outros usuários conectados. À medida que novos usuários se conectam ao contêiner com IDs exclusivos, o número de caixas aumentará.

Uma captura de tela de um navegador mostrando informações para quatro usuários de contêiner diferentes.

Nota

Este tutorial pressupõe que você esteja familiarizado com a Visão Geral do Fluid Framework e que tenha concluído o Guia de início rápido. Você também deve estar familiarizado com os conceitos básicos do React, da criação de projetos React e do React Hooks.

Criar o projeto

  1. Abra um prompt de comando e navegue até a pasta pai onde você deseja criar o projeto; por exemplo, C:\My Fluid Projects.

  2. Execute o seguinte comando no prompt. (Observe que a CLI é npx, não npm. Ele foi instalado quando você instalou o Node.js.)

    npx create-react-app fluid-audience-tutorial
    
  3. O projeto é criado em uma subpasta chamada fluid-audience-tutorial. Navegue até ele com o comando cd fluid-audience-tutorial.

  4. O projeto utiliza as seguintes bibliotecas Fluid:

    Biblioteca Description
    fluid-framework Contém a estrutura de dados distribuídos SharedMap que sincroniza dados entre clientes.
    @fluidframework/azure-client Define a conexão com um servidor de serviço Fluid e define o esquema inicial para o contêiner Fluid.
    @fluidframework/test-client-utils Define o InsecureTokenProvider necessário para criar a conexão com um Serviço Fluido.

    Execute o seguinte comando para instalar as bibliotecas.

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

Codifique o projeto

Configurar variáveis de estado e visualização de componentes

  1. Abra o arquivo \src\App.js no editor de códigos. Exclua todas as instruções padrão import . Em seguida, exclua toda a marcação da return instrução. Em seguida, adicione instruções de importação para componentes e ganchos React. Observe que implementaremos os componentes importados AudienceDisplay e UserIdSelection nas etapas posteriores. O arquivo deve ter a seguinte aparência:

        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. Substitua TODO 1 pelo código abaixo. Esse código inicializa variáveis de estado local que serão usadas dentro do aplicativo. O displayAudience valor determina se renderizamos o componente AudienceDisplay ou o componente UserIdSelection (consulte TODO 2). O userId valor é o identificador de usuário com o qual se conectar ao contêiner e o containerId valor é o contêiner a ser carregado. As handleSelectUser funções e handleContainerNotFound são passadas como retornos de chamada para as duas visualizações e gerenciam transições de estado. handleSelectUser é chamado ao tentar criar/carregar um contêiner. handleContainerNotFound é chamado quando a criação/carregamento de um contêiner falha.

    Observe que os valores userId e containerId virão de um componente UserIdSelection através da handleSelectUser função.

        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. Substitua TODO 2 pelo código abaixo. Como dito acima, a displayAudience variável determinará se renderizamos o componente AudienceDisplay ou o componente UserIdSelection . Além disso, as funções para atualizar as variáveis de estado são passadas para componentes como propriedades.

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

Configurar o componente AudienceDisplay

  1. Crie e abra um arquivo \src\AudienceDisplay.js no editor de códigos. Adicione as seguintes instruções import:

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

    Observe que os objetos importados da biblioteca do Fluid Framework são necessários para definir usuários e contêineres. Nas etapas a seguir, AzureClient e InsecureTokenProvider serão usados para configurar o serviço do cliente (consulte TODO 1), enquanto o SharedMap será usado para configurar um containerSchema necessário para criar um contêiner (consulte TODO 2).

  2. Adicione os seguintes componentes funcionais e funções auxiliares:

        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
        }
    

    Observe que AudienceDisplay e AudienceList são componentes funcionais que lidam com a obtenção e renderização de dados de audiência, enquanto o tryGetAudienceObject método lida com a criação de serviços de contêiner e audiência.

Obter contêiner e público

Você pode usar uma função auxiliar para obter os dados Fluid, do objeto Audience, para a camada de exibição (o estado React). O tryGetAudienceObject método é chamado quando o componente de exibição é carregado depois que um ID de usuário é selecionado. O valor retornado é atribuído a uma propriedade de estado React.

  1. Substitua TODO 1 pelo código abaixo. Observe que os valores para userId userName containerId serão passados do componente Aplicativo . Se não containerIdhouver , um novo contêiner será criado. Além disso, observe que o containerId é armazenado no hash da URL. Um usuário que entra em uma sessão de um novo navegador pode copiar a URL de um navegador de sessão existente ou navegar e localhost:3000 inserir manualmente o ID do contêiner. Com essa implementação, queremos envolver a getContainer chamada em uma tentativa de captura no caso de o usuário inserir um ID de contêiner que não existe. Visite a documentação de contêineres para obter mais informações.

        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;
    

Colocar o público na montagem de componentes

Agora que definimos como obter o público fluido, precisamos dizer ao React para ligar tryGetAudienceObject quando o componente Exibição de público estiver montado.

  1. Substitua TODO 2 pelo código abaixo. Observe que o ID do usuário virá do componente pai como um ou user1 user2 random. Se o ID é random que usamos Math.random() para gerar um número aleatório como o ID. Além disso, um nome será mapeado para o usuário com base em seu ID, conforme especificado em userNameList. Por fim, definimos as variáveis de estado que armazenarão os membros conectados, bem como o usuário atual. fluidMembers armazenará uma lista de todos os membros conectados ao contêiner, enquanto currentMember conterá o objeto member que representa o usuário atual visualizando o contexto do navegador.

        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. Substitua TODO 3 pelo código abaixo. Isso chamará o tryGetAudienceObject quando o componente for montado e definirá os membros da audiência retornados como fluidMembers e currentMember. Nota, verificamos se um objeto audience é retornado no caso de um usuário inserir um containerId que não existe e precisamos retorná-los para a visualização UserIdSelection (props.onContainerNotFound() tratará de alternar a exibição). Além disso, é uma boa prática cancelar o registro de manipuladores de eventos quando o componente React é desmontado retornando 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. Substitua TODO 4 pelo código abaixo. Observe que, se o fluidMembers ou currentMember não tiver sido inicializado, uma tela em branco será renderizada. O componente AudienceList renderizará os dados do membro com estilo (a ser implementado na próxima seção).

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

    Nota

    Transições de conexão podem resultar em janelas de tempo curtas onde getMyself retorna undefined. Isso ocorre porque a conexão do cliente atual ainda não terá sido adicionada ao público, portanto, um ID de conexão correspondente não pode ser encontrado. Para impedir que o React renderize uma página sem membros do público, adicionamos um ouvinte para chamar updateMembers membersChangedo . Isso funciona porque o público do serviço emite um membersChanged evento quando o contêiner está conectado.

Criar a vista

  1. Substitua TODO 5 pelo código abaixo. Observe que estamos renderizando um componente de lista para cada membro passado do componente AudienceDisplay . Para cada membro, primeiro comparamos member.userId para currentMember.userId verificar se esse membro isSelf. Desta forma, podemos diferenciar o usuário cliente dos outros usuários e exibir o componente com uma cor diferente. Em seguida, enviamos o componente de lista para uma list matriz. Cada componente exibirá dados de membros, como userId userName e 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. Substitua TODO 6 pelo código abaixo. Isso renderizará todos os elementos membros que enviamos para a list matriz.

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

Configurar componente UserIdSelection

  1. Crie e abra um arquivo \src\UserIdSelection.js no editor de códigos. Este componente incluirá botões de ID de utilizador e campos de entrada de ID de contentor que permitem aos utilizadores finais escolher o seu ID de utilizador e sessão colaborativa. Adicione as seguintes import instruções e componentes funcionais:

    import { useState } from 'react';
    
    export const UserIdSelection = (props) => {
        // TODO 1: Define styles and handle user inputs
        return (
        // TODO 2: Return view components
        );
    }
    
  2. Substitua TODO 1 pelo código abaixo. Observe que a onSelectUser função atualizará as variáveis de estado no componente App pai e solicitará uma alteração de exibição. O handleSubmit método é acionado por elementos de botão que serão implementados em TODO 2. Além disso, o handleChange método é usado para atualizar a containerId variável de estado. Esse método será chamado a partir de um ouvinte de eventos do elemento de entrada implementado no TODO 2. Além disso, observe que atualizamos o containerId be obtendo o valor de um elemento HTML com o id containerIdInput (definido em 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. Substitua TODO 2 pelo código abaixo. Isso renderizará os botões de ID do usuário, bem como o campo de entrada de ID do contêiner.

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

Inicie o servidor Fluid e execute o aplicativo

Nota

Para corresponder ao resto deste tutorial, esta seção usa npx e npm comandos para iniciar um servidor Fluid. No entanto, o código neste artigo também pode ser executado em um servidor Azure Fluid Relay. Para obter mais informações, consulte Como provisionar um serviço do Azure Fluid Relay e Como conectar-se a um serviço do Azure Fluid Relay

No prompt de comando, execute o seguinte comando para iniciar o serviço Fluid.

npx @fluidframework/azure-local-service@latest

Abra um novo prompt de comando e navegue até a raiz do projeto; por exemplo, C:/My Fluid Projects/fluid-audience-tutorial. Inicie o servidor de aplicativos com o seguinte comando. O aplicativo é aberto no navegador. Esta operação poderá demorar alguns minutos.

npm run start

Navegue até uma localhost:3000 guia do navegador para visualizar o aplicativo em execução. Para criar um novo contêiner, selecione um botão de ID de usuário deixando a entrada de ID de contêiner em branco. Para simular um novo usuário ingressando na sessão de contêiner, abra uma nova guia do navegador e navegue até localhost:3000. Desta vez, insira o valor de ID do contêiner que pode ser encontrado na url http://localhost:3000/#da primeira guia do navegador.

Nota

Pode ser necessário instalar uma dependência adicional para tornar esta demonstração compatível com o webpack 5. Se você receber um erro de compilação relacionado a um pacote "buffer" ou "url", execute npm install -D buffer url e tente novamente. Isso será resolvido em uma versão futura do Fluid Framework.

Próximos passos

  • Tente estender a demonstração com mais pares chave/valor no additionalDetails campo em userConfig.
  • Considere integrar o público em um aplicativo colaborativo que utiliza estruturas de dados distribuídas, como SharedMap ou SharedString.
  • Saiba mais sobre o Público-alvo.

Gorjeta

Quando você faz alterações no código, o projeto será reconstruído automaticamente e o servidor de aplicativos será recarregado. No entanto, se você fizer alterações no esquema de contêiner, elas só terão efeito se você fechar e reiniciar o servidor de aplicativos. Para fazer isso, dê foco ao prompt de comando e pressione Ctrl-C duas vezes. Em seguida, execute npm run start novamente.