React+ASP.NET中VideoSDK的onMeetingJoined无法获取更新后的组件状态
解决React闭包导致VideoSDK回调无法获取最新状态的问题
这个问题的核心是闭包陷阱:onMeetingJoined回调在组件初始渲染时被创建,它捕获了当时isCreator、gameHash等状态的初始值,后续状态更新时该回调不会自动重新生成,因此始终拿到旧值。以下是具体解决方案:
1. 使用useRef同步最新状态
通过useRef保存状态的最新值,因为ref的current属性是可变的,不会被闭包锁定,回调中直接访问ref.current就能拿到最新状态。
import { useRef, useEffect, useCallback } from 'react'; // 定义ref同步状态 const isCreatorRef = useRef(isCreator); const gameHashRef = useRef(gameHash); const minutesRef = useRef(minutes); const assetRef = useRef(asset); // 监听状态变化,同步更新ref useEffect(() => { isCreatorRef.current = isCreator; }, [isCreator]); useEffect(() => { gameHashRef.current = gameHash; }, [gameHash]); useEffect(() => { minutesRef.current = minutes; }, [minutes]); useEffect(() => { assetRef.current = asset; }, [asset]);
2. 重构onMeetingJoined回调
用useCallback包裹回调(确保VideoSDK能感知到回调更新),在回调中使用ref的current属性访问最新状态:
const onMeetingJoined = useCallback(() => { meetingAPI.muteMic(); meetingAPI.disableWebcam(); if (isCreatorRef.current) { const intervalId = setInterval(async () => { // 从ref中获取最新状态 const currentMinutes = minutesRef.current; const currentGameHash = gameHashRef.current; const currentAsset = assetRef.current; console.log("minutes", currentMinutes + currentGameHash.ActivePlayers.length); if (currentMinutes + currentGameHash.ActivePlayers.length >= currentAsset.VideoTime - 10 * currentGameHash.ActivePlayers.length) { setVideoMinutesRunoutModalOpen(true); clearInterval(intervalId); // 触发后清理定时器,避免重复执行 } }, 1000 * 60); setTimerId(intervalId); } setIsMeetingJoined(true); }, []); // 依赖为空,因为所有状态都通过ref访问 // 传递回调给useMeeting const meetingAPI = useMeeting({ onMeetingJoined });
3. 清理定时器(避免内存泄漏)
在组件卸载或状态变化时,及时清理定时器:
useEffect(() => { return () => { if (timerId) { clearInterval(timerId); } }; }, [timerId]); // 额外处理isCreator变化的场景:如果创建者身份改变,重新调整定时器 useEffect(() => { if (isMeetingJoined) { // 如果不再是创建者,清除现有定时器 if (!isCreatorRef.current && timerId) { clearInterval(timerId); setTimerId(null); } // 如果变为创建者,重新创建定时器 else if (isCreatorRef.current && !timerId) { const intervalId = setInterval(async () => { const currentMinutes = minutesRef.current; const currentGameHash = gameHashRef.current; const currentAsset = assetRef.current; if (currentMinutes + currentGameHash.ActivePlayers.length >= currentAsset.VideoTime - 10 * currentGameHash.ActivePlayers.length) { setVideoMinutesRunoutModalOpen(true); clearInterval(intervalId); } }, 1000 * 60); setTimerId(intervalId); } } }, [isMeetingJoined, isCreator]);
这样修改后,onMeetingJoined回调以及内部的定时器就能始终获取到isCreator、gameHash等状态的最新值。
内容的提问来源于stack exchange,提问作者Varenytsia
相关产品推荐
相关产品推荐

