【问题标题】:React, Node.js EvenEmitting on Express route to socket.ioReact,Node.js EvenEmitting 在 Express 路由到 socket.io
【发布时间】:2021-05-14 04:31:03
【问题描述】:

我正在使用socket.io 向客户端发送消息,我知道我可以使用快速路由的HTTP 响应来完成此示例,但在实际场景中,我会在获取数据时发出来自 API。

但是这个例子复制了我现在遇到的问题:

当我单击客户端上的按钮时,我向快速路由发出 get 请求,我的意图是在单击后立即记录发出消息,但我必须双击才能获取消息打印出来的。

server.js

import express from 'express'
import { createServer } from 'http'
import { Server } from 'socket.io'
import route from './route.js'
import { EventEmitter } from 'events'

const app = express()
const httpServer = createServer(app)
const io = new Server(httpServer, {
  cors: true,
  origins: [`http://locahost:4000}`]
})
const myEmitter = new EventEmitter()

app.use('/route', route)
app.set('event', myEmitter) // Attach the event emitter to use on routes

const connections = []

io.on('connection', (socket) => {
  connections.push(socket)
  console.log(`Socket id ${socket.id} connected`)

  socket.on('disconnect', () => {
    connections.splice(connections.indexOf(socket), 1)
  })
})

// Socket.io emit generator on an EventEmitter listener
myEmitter.on('my-event', (data) => {
  connections.forEach((socket) => {
    socket.emit('notify', data)
  })
})

httpServer.listen(4000, () => console.log(`App listening on port 4000.`))

route.js - 快速路线

import { Router } from 'express'

const router = Router()

router.get('/', async (req, res) => {
  // Import the EventEmitter
  const event = req.app.get('event')
  // Here I send the string to the EventEmitter 
  event.emit('my-event', 'Hello from route')

  res.send({ ok: true })
})

export default router

客户端 - 点击事件调用的 React 函数

// To get the message logged, I am having to run this function twice
const callRoute = () => {
  // Initialize socket
  const socket = socketIOClient('http://localhost:4000')
  // I request the express route with axios
  await axios('/route')
  // Then I want to print the message
  socket.on('notify', (data) => {
    console.log(data)
  })
}

【问题讨论】:

    标签: node.js reactjs express sockets


    【解决方案1】:

    我发现了问题,我只需要在客户端稍作改动:

    而不是在功能组件内部初始化套接字,它必须在它之外,然后使用useEffect 来监听发射

    // Declare it before the app
    const socket = socketIOClient('http://localhost:4000')
    
    
    // Main functional component
    const App = () => {
    
      // Here initialize the socket.io listener
      useEffect(() => {
        socket.on('notify', (data) => {
          console.log(data)
        })
      }, [])
    
      // Also disconnect if unmounts
      useEffect(() => () => socket.disconnect(), [])
    
      // And now I can connect to the route
      const callRoute = () => {
        await axios('/route')
      }
    ....
    

    此外,如果您想使用此设置向特定客户端发出(我很难找到),请执行以下操作:

    在客户端获取浏览器socket.id并将其置于状态

    const [clientID, setClientID] = useState('')
    
    useEffect(() => {
      socket.on('connect', () => {
        setClientID(socket.id)
      })
    
      socket.on('notify', (data) => {
        console.log(data)
      })
    }, [])
    
    // Then send the clientID to the route
    const callRoute = () => {
     await axios('/route', { params: { clientID } })
    }
    
    

    在路由上传递clientID

    event.emit('my-event', { 
      message: 'Hello from route', 
      socketID: req.query.clientID 
    })
    

    然后在服务器上将您的发射器更改为此

    myEmitter.on('my-event', (data) => {
      io.to(data.socketID).emit('notify', data.message)
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-30
      • 2017-10-07
      • 2016-09-20
      • 2019-09-02
      • 2015-01-03
      相关资源
      最近更新 更多