为什么 socket.io 事件会从 react 中多次触发?

Why is socket.io event firing multiple times from react?

提问人:FiFi 提问时间:4/12/2022 最后编辑:FiFi 更新时间:8/17/2022 访问量:1773

问:

我有一个连接事件,一旦我登录,我总是到达主屏幕,在主屏幕的 useEffect 上,我有 socket.io 客户端“连接”事件,如下所示。localStorage authToken 是在密码匹配后在登录屏幕上设置的。即使我关闭了 React Strict Mode,我也看到 connect 事件多次触发。

问题似乎出在客户端,因为第二个 useEffect 上的控制台 .log 多次触发。 我应该如何设置 socket.io,使其仅在 HomeScreen 渲染后触发一次?

useEffect(() => {
        if(localStorage.getItem('authToken') && !localStorage.getItem('showedLoginStatus')){
            toast.success("Login successful!");
            localStorage.setItem('showedLoginStatus', 'showed');
        }

        setSocket(io.connect(backendLink));
    }, [])

    useEffect(() => {
        console.log(socket, localStorage.getItem('authToken'));
        socket?.emit("newUser", localStorage.getItem('authToken'));
    }, [socket, localStorage.getItem('authToken')])

后端 socket.io 代码如下:

            socket.on("newUser", async (jwtToken) => {
                const user = await findUserFromJWT(jwtToken);
                addNewUser(user._id, socket.id);
                console.log('connect print'); printUsers();
            })

仅 1 次登录后服务器端的控制台 .log:

connect print
{
  userID: new ObjectId("6243ff45c46997fa04ea6e29"),
  socketID: '_-9y81H4P7PaUt19AAAB'
}
{
  userID: new ObjectId("6243ff45c46997fa04ea6e29"),
  socketID: 'cjU_JmCqUOMF619PAAAH'
}
JavaScript 节点.js ReactJS WebSocket socket.io

评论

0赞 FiFi 4/12/2022
这是因为服务器重新启动而发生的吗?如何确保情况并非如此?
0赞 yeahman14 4/12/2022
如果从 useEffect 的依赖项中删除 localStorage.getItem('authToken') 会发生什么?
0赞 FiFi 4/12/2022
这是一样的,因为在第二个 useEffect 的所有控制台 .log 上,authToken 始终存在,就像保持不变一样
0赞 FiFi 4/12/2022
有时有效,有时无效。第一次第二次 useEffect 渲染时,套接字为 null,所以我猜它不应该因为套接字而发出?。然后第二个 useEffect 使用有效的套接字进行渲染,这是第二次 useEffect 最后一次触发,那么为什么服务器上会触发多个事件调用呢?
0赞 Seba99 4/12/2022
如果可选的链把事情搞砸了怎么办?尝试将 your 封装在 ?socket.emit()if(!!socket){}

答:

0赞 arfi720 4/12/2022 #1

不完全确定,但是,看看这个答案,似乎将 localStorage 放在 useEffect 依赖项中并不是最好的主意。

不过,为了解决双重调用,根据我的经验,最好使用状态来跟踪 newUser 调用是否完成:

const [newUserRegistered, setNewUserRegistered] = useState(false);

useEffect(() => {
    const setNewUser = () => {
        if(window.localStorage('newUser') && socket && !newUserRegistered){
            //do your socket thing, then
            setNewUserRegistered(true);
        }
    }
    
    window.addEventListener('storage', setNewUser);

    return() => {
        window.removeEventListener('storage', setNewUser)
    }
}, [socket, newUserRegistered])
-1赞 Selcukusu 8/17/2022 #2

尝试删除

<React.StrictMode>
    //your code
</React.StrictMode>

index.js 中的标签