Next.js中requestAnimationFrame数据采集循环无法停止问题
解决Next.js中Teachable Machine数据采集循环无法停止的问题
问题根源
你遇到的是React状态的闭包陷阱:dataGatherLoop函数启动时捕获了当时的gatherDataState值,后续状态更新后,循环内部读取的依然是旧的闭包值,导致无法识别停止信号。
解决方案:用useRef跟踪最新状态和动画帧ID
useRef的current属性是可变的,不会被闭包锁定,能始终获取最新状态;同时用它保存requestAnimationFrame的ID,确保能精准取消循环。
完整代码示例
import { useState, useEffect, useRef } from 'react'; const STOP_DATA_GATHER = -1; export default function TeachableMachine() { const [gatherDataState, setGatherDataState] = useState(STOP_DATA_GATHER); // 跟踪最新的采集状态 const gatherDataRef = useRef(gatherDataState); // 保存动画帧ID,用于取消循环 const animationIdRef = useRef(null); // 同步状态到ref,状态变为停止时立即取消循环 useEffect(() => { gatherDataRef.current = gatherDataState; if (gatherDataState === STOP_DATA_GATHER && animationIdRef.current) { cancelAnimationFrame(animationIdRef.current); animationIdRef.current = null; } }, [gatherDataState]); // 开始采集数据(鼠标按下触发) const startGatherData = (classId) => { setGatherDataState(classId); }; // 停止采集数据(鼠标松开触发) const stopGatherData = () => { setGatherDataState(STOP_DATA_GATHER); }; const dataGatherLoop = async () => { // 读取最新的采集状态 const currentState = gatherDataRef.current; if (currentState === STOP_DATA_GATHER) return; // 执行数据采集逻辑:提取视频帧、转换为Tensor等 // 示例:假设video是你的视频元素引用 // const video = document.getElementById('webcam'); // const tensor = tf.browser.fromPixels(video); // 处理张量并添加到数据集... // 继续循环,保存动画帧ID animationIdRef.current = requestAnimationFrame(dataGatherLoop); }; // 状态变为非停止时启动循环 useEffect(() => { if (gatherDataState !== STOP_DATA_GATHER && !animationIdRef.current) { animationIdRef.current = requestAnimationFrame(dataGatherLoop); } }, [gatherDataState]); return ( <div> <button onMouseDown={() => startGatherData(1)} onMouseUp={stopGatherData} onMouseLeave={stopGatherData} {/* 鼠标移出按钮也停止,避免异常 */} > 采集类别1数据 </button> {/* 其他类别按钮、视频元素等 */} </div> ); }
关键改进点
- 用
gatherDataRef同步状态:每次gatherDataState更新时,都会把最新值同步到ref.current,循环内读取的始终是当前最新状态。 - 精准控制动画帧:用
animationIdRef保存每次requestAnimationFrame的ID,状态变为停止时直接取消该ID对应的循环,避免残留。 - 补充
onMouseLeave事件:防止鼠标意外移出按钮时,无法触发停止逻辑。
内容的提问来源于stack exchange,提问作者bene
相关产品推荐
相关产品推荐

