Javascript 奇怪的行为Socket.io并使用钩子进行反应

Javascript 奇怪的行为Socket.io并使用钩子进行反应,javascript,node.js,reactjs,socket.io,react-hooks,Javascript,Node.js,Reactjs,Socket.io,React Hooks,我目前正在学习Socket.io和React with Hooks,我正在尝试制作一个计时器,当您按下start按钮时,计时器将启动,并且每秒使用Socket.io向服务器发送处于该状态的时间 服务器得到正确的时间,我将响应发送回客户端 问题是,当I console.log在客户机中记录该响应时,它会多次获得该响应 这是我的index.js(节点) 这是我的React应用程序 App.js import React from "react"; import io from "socket.io

我目前正在学习Socket.io和React with Hooks,我正在尝试制作一个计时器,当您按下start按钮时,计时器将启动,并且每秒使用Socket.io向服务器发送处于该状态的时间

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

问题是,当I console.log在客户机中记录该响应时,它会多次获得该响应

这是我的index.js(节点)

这是我的React应用程序

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;
从“React”导入React;
从“socket.io客户端”导入io;
从“react router dom”导入{Route,Switch};
从“/components/Timer”导入TimerComponent;
常量应用=()=>{
const socket=io(“本地主机:8080”);
返回(
} />
);
};
导出默认应用程序;
定时器组件

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>
  );
}
import React,{useffect,useState}来自“React”;
从“react timer hook”导入{useStopwatch};
导出默认函数计时器({io}){
常量[isActive,setIsActive]=useState(false);
常数{秒、分钟、小时、开始、暂停、重置}=useStopwatch({
自动启动:错误
});
io.on('RECEIVE_MESSAGE',(data)=>{//这是多次打印
console.log('从服务器接收',数据)
});
useffect(()=>{
如果(isActive){
io.emit(‘发送时间’{
时间:`${formatDate(小时)}:${formatDate(分钟)}:${formatDate(秒)}`
})
}
});
const formatDate=t=>(t{
setIsActive(!isActive);
如果(isActive){
暂停();
}否则{
start();
}
};
常量handleReset=()=>{
重置();
setIsActive(假);
};
返回(
{formatDate(小时)}:{formatDate(分钟)}:
{格式化日期(秒)}
{isActive?“Stop”:“Start”}
重置
);
}
如果我在app.js上添加事件处理程序(io.on('RECEIVE MESSAGE'))而不是计时器组件,它将正常工作(每秒只打印一次)

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

谢谢!

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

当页面呈现时,useffect()也会运行那么多次。但是如果在useffect()第二个参数中传递
[isActive]
,则useffect()将跟踪
isActive
,如果它发生更改,则只会运行useffect()


阅读

每次组件函数运行时,您都在添加一个新的
io。在
处理程序上,不要覆盖以前的处理程序。您知道如何设置吗?我尝试使用道具从导入中获取io,但我得到了相同的结果。非常感谢。谢谢!
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>
  );
}
useEffect(() => {
    if(isActive){
        io.emit('SEND_TIME',{
            time:`${formatDate(hours)}:${formatDate(minutes)}:${formatDate(seconds)}`
        })
    }
  },[isActive]);