为什么我的 socket.io 事件侦听器在 UI 组件上正常工作,但在 React 中的另一个组件上不起作用? [英] Why is my socket.io event listener works properly on a UI component but doesn't work on the other in React?

查看:69
本文介绍了为什么我的 socket.io 事件侦听器在 UI 组件上正常工作,但在 React 中的另一个组件上不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解决一个奇怪的错误(或者我可能因为我是 React 的新手而使它变得奇怪).我正在使用 React 和 TypeScript 构建一个应用程序,该应用程序允许我订阅某些主题,以便接收值并在 UI 中实时显示.

I have a weird bug that I'm trying to solve (or maybe I made it weird because I'm new to React). I'm using React and TypeScript to build an app that will allows me to subscribe to certain topics in order to receive values and show me in the UI in real time.

简而言之,我有一个包含主题的数组,我正在遍历这个数组以动态创建 UI 元素:

Briefly, I have an array containing topics and I'm looping through this array to dynamically create UI elements:

{selectedTopics.map((topic: any, idx: number) =>
        < Slider key={idx}
          topic={topic}
          socket={socket} // socket.on is working on this component
          selectedTopics={selectedTopics}
          setSelectedTopics={(topics: any) => setSelectedTopics(topics)}

        />)
      }
       <CustomComponent socket={socket} /> // socket.on is not working on this component

如您所见,我正在我的根应用程序中创建一个全局套接字连接,并将其作为道具传递给子级.然后,我在子组件中调用 props.socket.on('subscribe', callback); .

As you can see I'm creating a global socket connection in my root app and passing it to children as prop. Then, I'm calling props.socket.on('subscribe', callback); In the child component.

这是我的子组件(滑块)的代码:

Here is my code for the child component (Slider):

const Slider: React.FC<{
  socket: SocketIOClient.Socket;
  topic: any;
  selectedTopics: any;
  setSelectedTopics: any;
}> = (props) => {

  const [realTimeValue, setRealTimeValue] = useState<string>("");
  const [loading, setLoading] = useState<boolean>(false);
  const [subscribed, setSubscribed] = useState<boolean>(false);

  
  const onSubscribe = (topic: any) => {
    
    props.socket.on("onSubscribe", (data: any) => {

     
        const name = data.Name;
        const payload = data.Value;

        console.log(`received response with name: ${name} and payload: ${payload}`);
      if (topic.name === name) {
        console.log(`topic received= ${name} correspond to tpic name = ${topic.name}`);
        setSubscribed(true);
        setRealTimeValue(payload);
        setLoading(false);

      }
      else {

        console.log(`received topic = ${name} but current was ${topic.name} `);
      }
      
      

    });
  }

  const subscribe = (topic: any) => {
    /* I'm invoking this function with a click button. So when the user clicks, then this function will be triggered.

    */
    const req = {
          subscribe: topic.Topic,
        }
     
    props.socket.emit('subscribe', req);
    setLoading(true);
    onSubscribe(topic);


  }
.
.
.

如您所见,我这样做是因为我需要将事件发送到我指定主题名称的服务器,以便对服务器说,嘿,我想订阅此特定主题.我不知道这是否是最好的方法,因为我为所有 UI 组件调用相同的事件和相同的回调函数.

As you can see, I'm doing this because I need to send the event to the server where I specify the topic name in order to say to the server, hey I want to subscribe this specific topic. I don't know if this is the best approach since I'm calling the same event and same callback function for all UI components.

这很好用,这不是我的问题.我的问题是我还将这个全局套接字对象传递给下一个 UI 组件,即 CustomComponent.这是我的代码的简化版本:

This works perfectly, this is not my issue. My issue is I'm passing this global socket object also to the next UI component, which is the CustomComponent. Here is a simplified version of my code:

import React, { useState, useEffect } from 'react';
import { IonLabel} from '@ionic/react';

const Custom: React.FC<{
  socket: SocketIOClient.Socket;
}> = (props) => {

  const [temp, setTemp] = useState("");


  const handle = (data: any) => {
        console.log(`**received ${data}`);
      setTemp("received");
    }

  useEffect(() => {
    
    console.log("useEffect called ..")
    console.log(`height: ${window.innerHeight} | width: ${window.innerWidth}`);
    
    props.socket.on('onCustom', handle);
    
  }, []) // I tried passing temp, setTemp and props.socket in the dependencies array but nothing worked. However, this works when I pass the handle function in the dep array or not pass any array at all. But not quite as expected because it renders many times until my app freezes.




  return (
        <IonLabel>{temp}</IonLabel>
  );
};

export default Custom;

如您所见,我使用 useEffect 钩子在组件安装时调用 socket.on,因为我希望它在组件安装时运行而不是由 Slider 组件中的按钮触发.

As you can see, I'm using useEffect hook to call socket.on when the component mounts, since I want it to run when the component mounts and not get triggered by a button like in the Slider component.

现在这不起作用,我无法使用从服务器发送的消息.就像我的 props.socket.on 不工作,这意味着它没有监听来自服务器的传入响应.令人惊讶的是,当我根本不传递数组依赖项或传递依赖项数组中的句柄函数时,这会起作用.但是,这每秒渲染数千次,一段时间后应用程序冻结,我无能为力.

Now this does not work and I'm not able to consume the messages sent from the server. It's like my props.socket.on is not working, which means that it is not listening on the incoming response from the server. Surprisingly, this works when I don't pass an array dependency at all or when I pass the handle function in the dependency array. However, this renders thousand times per second and after a while the app freezes and I can't do anything.

我在应用程序组件之外创建我的套接字实例,以便它不会一直呈现.我不知道这样做是否合适.所以我有这样的事情:

I'm creating my socket instance outside the app component so that it will not render all the time. I don't know if this is the appropriate way to do it. So I have something like this:

const socket = socketIOClient(serverHost);

const App: React.FC = () => {
.
.
.
.

如您所见,我在外部创建了套接字,我通过将其传递给子组件来在应用程序组件中使用它.

As you can see I'm creating the socket outside and them I'm using it in the app component by passing it to the children components.

推荐答案

我不确定这是否有效.尝试在 useEffect 回调中移动 handle 函数并在依赖项中添加 temp :

I'm not sure if this will work. Try to move the handle function inside useEffect callback and add the temp in the depedency:

useEffect(() => {
    
    console.log("useEffect called ..")
    console.log(`height: ${window.innerHeight} | width: ${window.innerWidth}`);
    
    props.socket.on('onCustom', (data: any) => {
        console.log(`**received ${data}`);
        setTemp("received");
    });
    
}, [temp])

这篇关于为什么我的 socket.io 事件侦听器在 UI 组件上正常工作,但在 React 中的另一个组件上不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆