كيفية: استخدام ميزات الجمهور في إطار عمل Fluid

في هذا البرنامج التعليمي، ستتعرف على استخدام إطار عمل Fluid 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.

إشعار

يفترض هذا البرنامج التعليمي أنك على دراية بنظرة عامة على إطار عمل Fluid وأنك قد أكملت QuickStart. يجب أن تكون على دراية أيضا بأساسيات 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 المطلوب لإنشاء الاتصال بخدمة Fluid.

    قم بتشغيل الأمر التالي لتثبيت المكتبات.

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

تعليمة برمجية للمشروع

إعداد متغيرات الحالة وعرض المكون

  1. افتح الملف \src\App.js في محرر التعليمات البرمجية. حذف كافة العبارات الافتراضية import . ثم احذف كافة العلامات من العبارة return . ثم أضف عبارات الاستيراد للمكونات وReact hooks. لاحظ أننا سننفذ مكونات 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
        );
        }
    
  2. استبدل 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]);
    
  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";
    

    لاحظ أن الكائنات المستوردة من مكتبة إطار عمل Fluid مطلوبة لتعريف المستخدمين والحاويات. في الخطوات التالية، سيتم استخدام AzureClient وConsentTokenProvider لتكوين خدمة العميل (راجع 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
        }
    

    لاحظ أن AudienceDisplay و AudienceList هما مكونان وظيفيان يتعاملان مع الحصول على بيانات الجمهور وعرضها بينما tryGetAudienceObject يعالج الأسلوب إنشاء خدمات الحاوية والجمهور.

الحصول على الحاوية والجمهور

يمكنك استخدام دالة مساعد للحصول على بيانات Fluid، من كائن Audience، إلى طبقة العرض (حالة React). tryGetAudienceObject يتم استدعاء الأسلوب عند تحميل مكون العرض بعد تحديد معرف المستخدم. يتم تعيين القيمة التي تم إرجاعها إلى خاصية حالة React.

  1. استبدل 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 عند تحميل مكون عرض الجمهور.

  1. استبدل TODO 2 بالتعليمات البرمجية التالية. لاحظ أن معرف المستخدم سيأتي من المكون الأصل إما أو user1user2random. إذا كان المعرف هو 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 عند تحميل المكون وتعيين أعضاء الجماعة المستهدفة التي تم إرجاعها إلى 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) };
        });
        }, []);
    
  3. استبدل TODO 4 بالتعليمات البرمجية التالية. ملاحظة، إذا لم تتم تهيئة fluidMembers أو currentMember ، يتم عرض شاشة فارغة. سيعرض مكون AudienceList بيانات العضو مع التصميم (ليتم تنفيذه في القسم التالي).

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

    إشعار

    يمكن أن تؤدي انتقالات الاتصال إلى نوافذ توقيت قصيرة حيث getMyself ترجع undefined. وذلك لأنه لن تتم إضافة اتصال العميل الحالي إلى الجمهور حتى الآن، لذلك لا يمكن العثور على معرف اتصال مطابق. لمنع React من عرض صفحة بدون أعضاء جمهور، نضيف وحدة استماع للاتصال updateMembers على membersChanged. يعمل هذا نظرا لأن جمهور الخدمة يصدر حدثا membersChanged عند توصيل الحاوية.

إنشاء طريقة العرض

  1. استبدل 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>
            );
        });
    
  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 الحصول على القيمة من عنصر 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);
        };
    
  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 وتشغيل التطبيق

إشعار

لمطابقة بقية هذه الكيفية، يستخدم 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. هذه المرة، أدخل قيمة معرف الحاوية التي يمكن العثور عليها من متابعة http://localhost:3000/#عنوان url لعلامة تبويب المستعرض الأولى .

إشعار

قد تحتاج إلى تثبيت تبعية إضافية لجعل هذا العرض التوضيحي متوافقا مع Webpack 5. إذا تلقيت خطأ في التحويل البرمجي يتعلق بحزمة "مخزن مؤقت" أو "url"، فيرجى التشغيل npm install -D buffer url والمحاولة مرة أخرى. سيتم حل هذا في إصدار مستقبلي من إطار عمل Fluid.

الخطوات التالية

  • حاول توسيع العرض التوضيحي مع المزيد من أزواج المفاتيح/القيم في الحقل في additionalDetailsuserConfig.
  • ضع في اعتبارك دمج الجمهور في تطبيق تعاوني يستخدم بنيات البيانات الموزعة مثل SharedMap أو SharedString.
  • تعرف على المزيد حول Audience.

تلميح

عند إجراء تغييرات على التعليمات البرمجية، سيعيد المشروع إنشاءه تلقائيا وسيعيد خادم التطبيق تحميله. ومع ذلك، إذا قمت بإجراء تغييرات على مخطط الحاوية، فلن تسري إلا إذا قمت بإغلاق خادم التطبيق وإعادة تشغيله. للقيام بذلك، امنح التركيز إلى موجه الأوامر واضغط على Ctrl-C مرتين. ثم قم بتشغيل npm run start مرة أخرى.