具有socket.io状态的UseEffect挂钩在套接字处理程序中不持久

时间:2019-02-22 09:34:48

标签: reactjs socket.io webrtc react-hooks

我有以下反应成分

function custom_editor_styles() {
    add_editor_style('editor-styles.css');
}

add_action('init', 'custom_editor_styles');

它唯一的状态是调用中使用useState钩子定义它的参与者的哈希表。

然后我正在使用useEffect来监听聊天室的套接字事件,而只是4个事件

然后在那之后,我针对服务器上执行顺序的那些事件定义4个回调处理程序

最后,我还有另一个回调函数,该函数传递给列表中的每个子参与者,以便子组件创建其rtcPeer对象后,将其发送给父对象,以将其设置在参与者的hashTable的参与者对象上。

流程类似于参与者加入会议室->调用 existingParticipants 事件->创建本地参与者并将其添加到参与者hashTable中,然后-> receveVideoAnswer 和<如屏幕快照所示,strong>候选人多次被服务器发出

状态为空的第一个事件,其后的两个事件为空,然后再次为空,此模式将不断重复一个空状态,然后以下两个是正确的,我不知道状态是怎么回事

enter image description here

1 个答案:

答案 0 :(得分:1)

困难的是,您遇到了一些相互影响的问题,这使您的故障排除感到困惑。

最大的问题是您正在设置多个套接字事件处理程序。每次重新渲染时,您都在调用socket.on,而从未调用过socket.off

您需要使用以下两种方法之一:

  • 设置单个套接字事件处理程序。使用这种方法,您将为useEffect使用一个空的依赖项数组,但这意味着您无法在效果内的任何地方引用participants 任何地方(包括所有称为由您的消息处理程序)。如果您确实引用了participants,则将在第一次重新渲染后引用它的旧版本。

  • 针对participants进行的每次更改都设置一个新的套接字事件处理程序。为了使其正常工作,您需要删除以前的事件处理程序,否则您将拥有与渲染器相同数量的事件处理程序。当您有多个事件处理程序时,创建的第一个事件处理程序将始终使用participants的第一个版本(空),第二个将始终使用participants的第二个版本,等等。

无论哪种情况,如果您将消息处理程序移出呈现函数并显式传递其依赖项,那么我认为您将更容易理解代码的作用。

第二个选项使用起来更加灵活,因为它使得可以在participants功能更新之外处理setParticipants,因此,我将仅演示该选项。使用此选项,无需在setParticipants中使用功能更新语法,但是您确实需要始终使用从useEffect返回的清除方法来删除以前的事件处理程序。

这是第二个选项的代码(我没有尝试执行此代码,因此我不保证自己没有语法上的小问题):

const messageHandler = (message, participants, setParticipants) => {
    console.log('Message received: ' + message.event);

    const onExistingParticipants = (userid, existingUsers) => {
        console.log('onExistingParticipants Called!!!!!');

        //Add local User
        const user = {
            id: userid,
            username: userName,
            published: true,
            rtcPeer: null
        };

        setParticipants({
            ...participants,
            [user.id]: user
        });

        existingUsers.forEach(function (element) {
            receiveVideo(element.id, element.name)
        })
    };

    const onReceiveVideoAnswer = (senderid, sdpAnswer) => {
        console.log('participants in Receive answer -> ', participants);
        console.log('***************')

        // participants[senderid].rtcPeer.processAnswer(sdpAnswer)
    };

    const addIceCandidate = (userid, candidate) => {
        console.log('participants in Receive canditate -> ', participants);
        console.log('***************');
        // participants[userid].rtcPeer.addIceCandidate(candidate)
    };

    const receiveVideo = (userid, username) => {
        console.log('Received Video Called!!!!');
        //Add remote User
        const user = {
            id: userid,
            username: username,
            published: false,
            rtcPeer: null
        };

        setParticipants({
            ...participants,
            [user.id]: user
        });
    };

    //Callback for setting rtcPeer after creating it in child component
    const setRtcPeerForUser = (userid, rtcPeer) => {
        setParticipants({
            ...participants,
            [userid]: {...participants[userid], rtcPeer: rtcPeer}
        });
    };

    switch (message.event) {
        case 'newParticipantArrived':
            receiveVideo(message.userid, message.username);
            break;
        case 'existingParticipants':
            onExistingParticipants(
                    message.userid,
                    message.existingUsers
            );
            break;
        case 'receiveVideoAnswer':
            onReceiveVideoAnswer(message.senderid, message.sdpAnswer);
            break;
        case 'candidate':
            addIceCandidate(message.userid, message.candidate);
            break;
        default:
            break;
    }
};

function ConferencingRoom() {
    const [participants, setParticipants] = useState({});
    console.log('Participants -> ', participants);

    useEffect(() => {
        const handler = (message) => {messageHandler(message, participants, setParticipants)};
        socket.on('message', handler);
        return () => {
            // THIS IS THE IMPORTANT CHANGE
            socket.off('message', handler);
        }
    }, [participants]);

    return (
            <div id="meetingRoom">
                {Object.values(participants).map(participant => (
                        <Participant
                                key={participant.id}
                                participant={participant}
                                roomName={roomName}
                                setRtcPeerForUser={setRtcPeerForUser}
                                sendMessage={sendMessage}
                        />
                ))}
            </div>
    );
}