我正在尝试制作一个组件,当您添加任务时,事件侦听器会添加到 socketio 客户端。当服务器报告任务进度并且我想用新进度更新任务时,会触发该事件。
问题是,当我更新任务进度时,事件回调函数使用函数分配时组件的状态。如果“任务”状态在分配之前为空,则进度更新会删除该状态。
我不知道如何在回调函数中使用当前状态。 (进度更新在事件回调之外起作用)
这是一个最小的可重现示例:
import React, {useEffect, useRef, useState} from "react";
import axios from "axios";
import socketIOClient from "socket.io-client"
export default function TestComponent() {
const socketRef = useRef(null);
const [tasks, setTasks] = useState([]) // task: {id, name, time_start, progress}
useEffect(() => {
if (socketRef.current == null) {
socketRef.current = socketIOClient({path: "/api/socket.io"});
}
return () => {
socketRef.current.disconnect();
};
}, []);
function addTask(task) {
setTasks([...tasks, task]);
addTaskProgressEvent(task);
}
function addTaskProgressEvent(task) {
const event = "task:" + task.id + ":progress";
socketRef.current.on(event, (progress) => {
// update task progress (this failes!)
setTasks(tasks.map(list_task => list_task.id === task.id ?
{...list_task, progress: progress} : list_task))
console.log(progress);
})
}
function handleStartTask() {
axios.post("/api/task").then((response) => {
addTask(response.data);
});
}
return (
<div className="TestComponent">
<button onClick={handleStartTask}>
start task
</button>
</div>
);
}
您必须使用带有回调的setter,才能获取状态的当前值:
function addTaskProgressEvent(task) {
const event = "task:" + task.id + ":progress";
socketRef.current.on(event, (progress) => {
// update task progress (this failes!)
setTasks(oldTasks => oldTasks.map(list_task => list_task.id === task.id ?
{...list_task, progress: progress} : list_task))
console.log(progress);
})
}
试试这个
useEffect(() => {
if (!socketInstance) return; // if no socket instance is created return
from here
// if user has connections then update connection list with received
connections status update
socketInstance.on("getOnlineUsers", (data) => {
setConnections((oldConnections) => {
return oldConnections.length
? oldConnections
.filter((c) => c._id === data.userId)
.map((c) => {
c.isOnline = "1";
return c;
})
: oldConnections;
});
});
socketInstance.on("getOfflineUsers", (data) => {
setConnections((oldConnections) => {
return oldConnections.length
? oldConnections
.filter((c) => c._id === data.userId)
.map((c) => {
c.isOnline = "0";
return c;
})
: oldConnections;
});
});
// use socket to listen multiple events
// TODO listen to broadcast message from server & only update messages
array if upcoming message is for current user
socketInstance.on("message", (data) => {
console.log("socket message event", data);
});
return () => {
// remove socket event listeners once component unmounted
socketInstance.off("connect");
};
}, [socketInstance]);