You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 12:42:38