gpt4 book ai didi

reactjs - 服务器的 socket.io 监听器无缘无故地触发两次

转载 作者:行者123 更新时间:2023-12-04 11:31:32 25 4
gpt4 key购买 nike

我正在使用 express.js、react.js 和 socket.io 构建一个具有聊天功能的应用程序。 Here is a minimal version with the bug reproduced on Github .
问题是服务器的socket.on()总是开火两次,这对我来说毫无意义。
据我所知,客户端只发送一个 .emit , 但服务器的 .on不管连接了多少客户端,或者实际上我是如何重构代码的,总是会触发两次(我相当确定事件处理程序不会被绑定(bind)两次)。
发送客户端的表单(输入 + 按钮)将消息附加到其本地消息列表,然后分派(dispatch) MESSAGE_NEW到 reducer 。
这是第一个 Socket.js文件。

import React from 'react'
import socketio from 'socket.io-client'

export const socket = socketio.connect('ws://localhost:3001')
export const SocketContext = React.createContext()
这是来自 Chat.js 的提交处理程序代码(这似乎工作正常,只发送一次):
const handleSubmit = e => {
e.preventDefault()

if (message === '') return

setMessages(messages => [...messages, message])
dispatch({ type: 'MESSAGE_NEW', payload: message })
setMessage('')
}
这是 /Reducer.js , 其中 .emit是信号(似乎也工作正常,只发射一次)。
import { useContext } from 'react'
import { SocketContext } from './Socket'

export default function Reducer(state, action) {
const socket = useContext(SocketContext)

switch (action.type) {
case 'MESSAGE_NEW':
// this only fires once, as it should
console.log('emitting socket')
socket.emit('message:new', action.payload)
break

default:
return state
}
}
但这是来自 /server/index.js 的相关信息,这就是出错的地方。无论我尝试过什么, .on总是开火两次。
io.on('connection', socket => {
console.log('New client connected:', socket.id)

socket.on('message:new', message => {
// this always fires twice, i do not understand why
console.log('message:new: ', message, socket.id)
socket.broadcast.emit('message:new', message)
})
})
更新:我发现移动 socket.emit来自 Reducer.jshandleSubmitChat.js使它工作得很好。我不明白为什么因为 Reducer 不会触发两次。

最佳答案

根据 React documentation's on strict mode :

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

  • Class component constructor, render, and shouldComponentUpdate methods
  • Class component static getDerivedStateFromProps method
  • Function component bodies
  • State updater functions (the first argument to setState)
  • Functions passed to useState, useMemo, or useReducer

注意最后一行:传递给 useReducer 的函数将被调用两次;这就是为什么您的消息被发送两次的原因。您可以通过像这样更新 reducer 来确认这一点:
  case "MESSAGE_NEW":
alert("I'm running");
感谢 React.StrictMode,您会注意到此警报出现了两次.
如果删除 <React.StrictMode>包装在 src/App.js test消息将不再重复;然而,它并没有解决这里的潜在问题。
潜在的问题是你让你的 reducer (应该是纯的)执行不纯的副作用(在这种情况下,通过 websocket 发送消息)。另外,reducer 函数还有一个 useContext调用——从 React 的角度来看,这也是一个空操作,不是好的做法。
正如您在问题中遇到的那样,只需移动 socket.emit进入您的 handleSubmit你应该很高兴去。或者,如果您想走 reducer 路线,您可以考虑更复杂的设置;一些流行的配置包括 Redux + Redux Thunk 或 Redux + Redux Saga。你的旅费可能会改变。

关于reactjs - 服务器的 socket.io 监听器无缘无故地触发两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68987508/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com