Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Q&A] React 18 useEffect 在 Strict Mode 下執行兩次,導致 join 被重複呼叫 #132

Open
linyawun opened this issue Feb 14, 2025 · 1 comment
Assignees
Labels
question Further information is requested

Comments

@linyawun
Copy link

問題描述

在 React 18 開發環境(StrictMode 啟用)下,useEffect 會執行兩次,導致以下執行順序:

joinRoom ➡ handleLeave ➡ joinRoom

由於 handleLeave 是非同步函式,在 handleLeave 執行完成前,React 就再次執行 joinRoom,導致「重複進房」錯誤。
雖然程式中已經有 isJoining 和 isLeaving 來避免重複執行,但在 StrictMode 的雙重執行下,它們的狀態更新可能還沒完成,就觸發了第二次 joinRoom,導致檢查條件失效。

重現步驟

  1. 在 React 18 專案中啟用 StrictMode。
  2. useEffect 中執行 joinRoom,並在 Cleanup 時執行 handleLeave
useEffect(() => {
  if (!isTRTCReady && connectTrtc) {
    const joinRoomHandler = async () => {
      await joinRoom();
    };
    joinRoomHandler();

    return () => {
      handleLeave();
    };
  }
}, [connectTrtc, isTRTCReady, joinRoom, handleLeave]);

joinRoomhandleLeave 內容如下:

const joinRoom = async () => {
  if (isJoining || isJoined) return;
  
  setIsJoining(true);
  await initClient();
  
  try {
    await TRTCClient.current.join({ roomId, role });
    setIsJoined(true);
    addUser(uid, 'local');
    privateStartGetAudioLevel();
  } catch (error) {
    setIsJoining(false);
    console.error('join room failed', error);
  } finally {
    setIsJoining(false);
  }
};

const handleLeave = async () => {
  if (!TRTCClient.current || isLeaving) return;

  setIsLeaving(true);
  privateStopGetAudioLevel();
  
  if (isPublished) await handleUnPublish();
  
  try {
    await TRTCClient.current.leave();
    removeUser(uid, 'local');
    setIsJoined(false);
  } catch (error) {
    console.error('leave room error', error);
  } finally {
    setIsLeaving(false);
  }
};
  1. 在 Console 觀察 log,會發現:
  • joinRoom 被執行兩次
  • handleLeave 在兩次 joinRoom 之間執行
  • handleLeave 還沒完成 就執行第二次 joinRoom,導致第一次 joinRoom 還未結束時,第二次 joinRoom 被觸發,出現「重複進房」錯誤
    Image

預期行為

第二次 joinRoom 執行時,handleLeave 應該已經完全完成、或是已取消第一次 joinRoom 的呼叫,不會出現重複進房錯誤

環境資訊

  • React 版本:18.0.0
  • TRTC JS SDK 版本:4.15.7
  • 開發模式:React 18 StrictMode 啟用

疑問

  1. TRTC Web SDK 是否有 API 來檢查 joinRoom 是否正在執行? 例如類似 isJoining 的內建狀態,讓我們能避免重複呼叫?
  2. 官方是否有建議的解法? 在 React 18 StrictMode 下,如何確保 joinRoomhandleLeave 不會發生競態問題?
@linyawun linyawun added the question Further information is requested label Feb 14, 2025
@linyawun linyawun changed the title [Q&A] React 18 useEffect 在 Strict Mode 下執行兩次,導致 join 被重複呼叫 [Q&A] React 18 useEffect 在 Strict Mode 下執行兩次,導致 join 被重複呼叫 Feb 14, 2025
@Rychou
Copy link
Collaborator

Rychou commented Feb 14, 2025

感谢您的反馈。

  1. TRTC Web SDK 是否有 API 來檢查 joinRoom 是否正在執行? 例如類似 isJoining 的內建狀態,讓我們能避免重複呼叫?

您使用的是 TRTC Web SDK v4 版本,这个版本没有类似的 api 检查 join 是否正在执行。需要你们根据 join api 返回的 promise 状态,来记录 isJoining 的状态进行处理。

  1. 官方是否有建議的解法? 在 React 18 StrictMode 下,如何確保 joinRoom 和 handleLeave 不會發生競態問題?

建议升级到 TRTC Web SDK v5 版本,v5 版本 sdk 增加了防止重复调用的拦截,如果业务侧重复调用进房相关接口,sdk 会拦截掉无效调用,参考 v5 ABORT_ERROR

需要注意的是,v5 和 v4 api 不兼容。参考文档:https://cloud.tencent.com/document/product/647/45558#9fc8d326-f880-475d-be53-aa20fc96f91f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants