不能在事件回调函数上使用 socketio 中的反应状态
Can't use react state inside a socketio on event callback function
我正在尝试制作一个组件,当您添加任务时,事件侦听器会添加到 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);
})
}
我正在尝试制作一个组件,当您添加任务时,事件侦听器会添加到 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);
})
}