异常行为Socket.io和带有钩子的React

时间:2019-07-19 21:59:14

标签: javascript node.js reactjs socket.io react-hooks

我目前正在使用带有Hooks的React与Hooks一起学习Socket.io,并尝试创建一个计时器,当您按下开始按钮时,计时器将启动,并且每秒钟使用socket.io发送到服务器的时间为

服务器获得正确的时间,我将响应发送回客户端。

问题是当我在客户端console.log该响应时,它多次获得响应示例

multiple console logs example

这是我的index.js(NODE)

const express = require('express');
const app = express();
const socket = require('socket.io');

server = app.listen(8080, function(){
    console.log('Server is running on port 8080')
});

io = socket(server);

io.on('connection', (socket) => {
    socket.on('SEND_TIME', function(data){
        //here the data object is correct
        socket.emit('RECEIVE_MESSAGE', data); //sending back to client
    })
});

这是我的React App

App.js

import React from "react";
import io from "socket.io-client";
import { Route, Switch } from "react-router-dom";
import TimerComponent from "./components/Timer";

const App = () => {
  const socket = io("localhost:8080");
  return (
    <React.Fragment>
      <Switch>
        <Route path="/" exact render={(routeProps)=> <TimerComponent {...routeProps} io={socket} />
        } />
      </Switch>
    </React.Fragment>
  );
};

export default App;

计时器组件

import React, { useEffect, useState } from "react";
import { useStopwatch } from "react-timer-hook";

export default function Timer({io}) {
  const [isActive, setIsActive] = useState(false);
  const { seconds, minutes, hours, start, pause, reset } = useStopwatch({
    autoStart: false
  });

  io.on('RECEIVE_MESSAGE', (data)=>{ //This is printing multiple times
    console.log('RECIEVED FROM SERVER',data)
  });

  useEffect(() => {
    if(isActive){
        io.emit('SEND_TIME',{
            time:`${formatDate(hours)}:${formatDate(minutes)}:${formatDate(seconds)}`
        })
    }
  });

  const formatDate = t => (t <=9)?`0${t}`:t;

  const handleStart = () => {
    setIsActive(!isActive);
    if (isActive) {
      pause();
    } else {
      start();
    }
  };

  const handleReset = () => {
    reset();
    setIsActive(false);
  };

  return (
    <div style={{ textAlign: "center" }}>
      <div style={{ fontSize: "100px" }}>
        <span>{formatDate(hours)}</span>:<span>{formatDate(minutes)}</span>:
        <span>{formatDate(seconds)}</span>
      </div>
      <button onClick={handleStart}>{isActive ? "Stop" : "Start"}</button>
      <button onClick={handleReset}>Reset</button>
    </div>
  );
}

如果我在app.js上添加事件处理程序(io.on('RECEIVE MESSAGE'))而不是Timer组件,它将正常工作(每秒仅打印一次)

我认为该问题与react useEffect挂钩和渲染行为有关

谢谢!

1 个答案:

答案 0 :(得分:0)

使用useEffect()时,请将[isActive]数组传递给useEffect()方法的第二个参数。

useEffect(() => {
    if(isActive){
        io.emit('SEND_TIME',{
            time:`${formatDate(hours)}:${formatDate(minutes)}:${formatDate(seconds)}`
        })
    }
  },[isActive]);

页面呈现时,useEffect()也会运行多次。但是,如果您在useEffect()的第二个参数中传递[isActive],则useEffect()将跟踪isActive,如果更改,则仅useEffect()将运行。

阅读useEffect API docs