简体   繁体   English

反应 - state 变量不反映变化

[英]React - state variable not reflecting changes

I am working on adding websockets to my Node/React app to automatically reflect changes to all the clients.我正在努力将 websockets 添加到我的 Node/React 应用程序中,以自动将更改反映到所有客户端。 So I have a websockets helper module that has onclose, onopen and onmessage events as well as a readyState function.所以我有一个 websockets 助手模块,它有 onclose、onopen 和 onmessage 事件以及 readyState function。 So my component that needs the updated websocket values makes a call to that module and gets back data.因此,需要更新的 websocket 值的组件调用该模块并取回数据。 That data variable is coming over empty, but when I console it out in the onmessage event in the module itself, it has all the info I want.该数据变量是空的,但是当我在模块本身的 onmessage 事件中对其进行控制台时,它具有我想要的所有信息。

So here is how I call the websocket module in my component:所以这就是我如何在我的组件中调用 websocket 模块:

const onConnected = (socket) => {
    socket.send(
        JSON.stringify({
            eventType: 'clientCount'
        })
    );
};
    const { socket, readyState, reconnecting, data } = useWebsocket({
        url: wsURL + ':' + process.env.REACT_APP_WS_PORT,
        onConnected
    });

I have a useEffect that should spit out the updated values from data:我有一个 useEffect 应该从数据中吐出更新的值:

useEffect(() => {
    console.log('data changed!!!!');
    console.log({ data });
    console.log({ socket });
    console.log({ readyState });
    if (data) {
        setNumberClients(data.numberClients);
        setNumberIpads(data.numberIpads);
    }
}, [data, readyState]);

And finally here is my websockets module itself:最后是我的 websockets 模块本身:

import { useState, useEffect, useRef } from 'react';

export default function useWebsocket({ url, onConnected }) {
    const [data, setData] = useState([]);
    const [reconnecting, setReconnecting] = useState(false);
    const socket = useRef(null);

    useEffect(() => {
        console.log('running socket hook');
        socket.current = new WebSocket(url);

        socket.current.onopen = () => {
            console.log('connected');
            onConnected(socket.current);
        };

        socket.current.onclose = () => {
            console.log('closed');
            if (socket.current) {
                if (reconnecting) return;
                setReconnecting(true);
                setTimeout(() => setReconnecting(false), 2000);
                socket.current.close();
                socket.current = undefined;
            }
        };

        socket.current.onmessage = (e) => {
            const wsData = JSON.parse(e.data);
            console.log('message received ', wsData);
            //setData((prev) => [...prev, wsData]);
            setData(wsData);
        };

        return () => {
            socket.current.close();
            socket.current = null;
        };
    }, [reconnecting, url]);

    const readyState = () => {
        if (socket.current) {
            switch (socket.current.readyState) {
                case 0:
                    return 'CONNECTING';
                case 1:
                    return 'OPEN';
                case 2:
                    return 'CLOSING';
                case 3:
                    return 'CLOSED';
                default:
                    return;
            }
        } else {
            return null;
        }
    };

    return {
        socket: socket.current,
        readyState: readyState(),
        reconnecting,
        data
    };
}

So data is always an empty array when I console it out in my component.因此,当我在组件中对其进行控制台时,数据始终是一个空数组。 But in the websockets module, it(wsData) has the info I need.但是在 websockets 模块中,它(wsData)有我需要的信息。

One More Thing: I am following the tutorial here: https://github.com/devmentorlive/websocket-direct-chat-client/tree/2-as-a-hook/src/chat还有一件事:我正在关注这里的教程: https://github.com/devmentorlive/websocket-direct-chat-client/tree/2-as-a-hook/src/chat

Update 2: I have a github repo showing the exact issue here: https://github.com/dmikester1/websockets-test Use Server and Start scripts to kick things off.更新 2:我有一个 github 存储库在这里显示了确切的问题: https://github.com/dmikester1/websockets-test使用服务器和启动脚本来开始。

It's not a problem on front-end side.这不是前端的问题。

I think you have used useWebsocket hook twice - once in the SchedulePage and again in the ClientCountContainer so that you can check if 2 clients are displayed.我认为您已经使用了两次useWebsocket挂钩 - 一次在SchedulePage中,一次在ClientCountContainer中,以便您可以检查是否显示了2 clients

The problem is that the socket client you defined in ClientCountContainer component is not receiving the message from the server.问题是您在ClientCountContainer组件中定义的socket客户端没有收到来自服务器的消息。

After looking at the websocket server, I noticed that it broadcasts messages to websocket clients that are saved in clients array.查看 websocket 服务器后,我注意到它向保存在clients数组中的 websocket 客户端广播消息。 Not all the websocket client is saved in this array, but only the client which sends {eventType: 'connect'} message to the server is saved in that array.并非所有 websocket 客户端都保存在该数组中,但只有向服务器发送{eventType: 'connect'}消息的客户端保存在该数组中。

The websocket client you created using useWebsocket hook in SchedulePage component is saved in clients array on websocket server, because it first sends {eventType: 'connect'} message to the server.您使用SchedulePage组件中的useWebsocket钩子创建的 websocket 客户端保存在 websocket 服务器上的clients数组中,因为它首先向服务器发送{eventType: 'connect'}消息。 But the websocket client you created in ClientCountContainer is not saved in that array.但是您在ClientCountContainer中创建的 websocket 客户端并未保存在该数组中。

Therefore, the messages containing clientCount information is not sent to the second websocket client which is defined in ClientCountContainer .因此,包含clientCount信息的消息不会发送到ClientCountContainer中定义的第二个 websocket 客户端。

To get rid of this from happening, you can simply add this code snippet in the ClientCountContainer.js , which sends {eventType: 'connect} message to the server so that this client can be added to broadcast array.为了避免这种情况发生,您可以简单地在ClientCountContainer.js中添加此代码片段,它将{eventType: 'connect}消息发送到服务器,以便可以将此客户端添加到广播数组中。

    .....
    const onConnected = (socket) => {
        // Add these lines
        socket.send(
            JSON.stringify({
                eventType: 'connect'
            })
        );

        // This is the original line
        socket.send(
            JSON.stringify({
                eventType: 'clientCount'
            })
        );
    };
    ......

Please let me know if you have further issues.如果您还有其他问题,请告诉我。 Thanks.谢谢。

I think that the useEffect would have to run all the time, not only when ur url changed or when it is reconnecting.我认为 useEffect 必须一直运行,不仅在您的url更改或重新连接时。

Try giving this a try: https://stackoverflow.com/a/60161181/10691892试试这个: https://stackoverflow.com/a/60161181/10691892

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM