我有一个奇怪的错误正在尝试解决(或者我可能因为我是 React 新手而让它变得很奇怪)。我正在使用 React 和 TypeScript 构建一个应用程序,该应用程序允许我订阅某些主题,以便接收值并在 UI 中实时显示。
简而言之,我有一个包含主题的数组,我正在循环这个数组以动态创建 UI 元素:
{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);
在子组件中调用。
这是我的子组件(滑块)的代码:
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 组件调用相同的事件和相同的回调函数。
这很好用,这不是我的问题。我的问题是我还将这个全局套接字对象传递给下一个 UI 组件,即CustomComponent
. 这是我的代码的简化版本:
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 组件中的按钮触发。
现在这不起作用,我无法使用从服务器发送的消息。这就像我props.socket.on
的不工作,这意味着它没有监听来自服务器的传入响应。令人惊讶的是,当我根本不传递数组依赖项或当我在依赖项数组中传递句柄函数时,这会起作用。但是,这每秒渲染数千次,过了一段时间应用程序冻结了,我什么也做不了。
编辑
我正在应用程序组件之外创建我的套接字实例,以便它不会一直呈现。我不知道这是否是合适的方法。所以我有这样的事情:
const socket = socketIOClient(serverHost);
const App: React.FC = () => {
.
.
.
.
正如你所看到的,我在外面创建了套接字,我通过将它传递给子组件在应用程序组件中使用它。