我正在尝试了解 SignalR 的基础知识。我在 React 中创建了一个项目,在 asp.net core 6 中使用 Web api 创建了后端。在服务器端,我实现了 Hub 并从 React 连接到它。在客户端代码看起来像这样:
const [counter, setCounter] = useState(0);
const [connection, setConnection] = useState<HubConnection>();
const MyLog = (message: string) => {
console.log(message)
console.log(counter)
}
useEffect(() => {
connect();
}, []);
const connect = async (): Promise<void> => {
const connection = new HubConnectionBuilder()
.withUrl(import.meta.env.VITE_SIGNALR)
.configureLogging(LogLevel.Information)
.build();
connection.on("ReceiveMyMessage", (message) => {
MyLog(message);
});
await connection.start();
setConnection(connection);
};
所以基本上一切正常,当后端上的某种操作完成时,所有客户端上都会调用 MyLog(message) 函数,并且消息会被传递,这样就可以了。但是,正如您在代码中看到的,我还将此组件的计数器状态初始设置为 0。我还有一个按钮,用于在每次单击后将计数器状态增加 1。
它适用于客户端。所以我有新刷新的网站,计数器设置为 0 并且建立了 signalR 连接。然后我点击按钮 5 次,我可以在客户端日志中看到计数器状态为 5。但是当我从后端 MyLog 函数发送消息时,计数器的值为 0。换句话说,当我在反应组件中收到 SignalR 消息时,它不知道用户在浏览器中不断更新的组件的状态。
我做错了什么?
这是一个常见的 JavaScript 闭包问题,您可以使用
useRef
来修复它。
这是样本。
import React, { useState, useEffect, useRef } from 'react';
import { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
const TheTestComponent = () => {
const [counter, setCounter] = useState(0);
const [connection, setConnection] = useState<HubConnection>();
const counterRef = useRef(counter); // Add useRef here
// update the value of counter in counterRef
useEffect(() => {
counterRef.current = counter;
connect();
}, [counter]);
const MyLog = (message: string) => {
console.log(message);
console.log(counterRef.current); // save the latest value of counter in useRef
};
useEffect(() => {
const connect = async (): Promise<void> => {
const newConnection = new HubConnectionBuilder()
.withUrl(import.meta.env.VITE_SIGNALR)
.configureLogging(LogLevel.Information)
.build();
newConnection.on("ReceiveMyMessage", (message) => {
MyLog(message);
});
await newConnection.start();
setConnection(newConnection);
};
connect();
}, []);
// ...
return (
// ...
);
};
export default TheTestComponent;