diff --git a/packages/agora-rtc-react/src/hooks/client.ts b/packages/agora-rtc-react/src/hooks/client.ts index ebb4d70f..db5f0592 100644 --- a/packages/agora-rtc-react/src/hooks/client.ts +++ b/packages/agora-rtc-react/src/hooks/client.ts @@ -2,7 +2,7 @@ import type { ConnectionState, IAgoraRTCClient, UID } from "agora-rtc-sdk-ng"; import { useEffect, useState } from "react"; import { listen } from "../listen"; -import { timeout } from "../utils"; +import { joinDisposers, timeout } from "../utils"; import { useRTCClient } from "./context"; import { useAsyncEffect } from "./tools"; @@ -35,9 +35,15 @@ export function useIsConnected(client?: IAgoraRTCClient | null): boolean { useEffect(() => { if (resolvedClient) { setConnected(resolvedClient.connectionState === "CONNECTED"); - return listen(resolvedClient, "connection-state-change", state => { - setConnected(state === "CONNECTED"); - }); + let dispose: (() => void) | undefined; + return joinDisposers([ + listen(resolvedClient, "connection-state-change", state => { + dispose?.(); + // RTC is really connected after a short delay + dispose = timeout(() => setConnected(state === "CONNECTED"), 0); + }), + () => dispose?.(), + ]); } else { setConnected(false); } @@ -58,6 +64,7 @@ export function useCurrentUID(client?: IAgoraRTCClient | null): UID | undefined if (resolvedClient) { return listen(resolvedClient, "connection-state-change", state => { if (state === "CONNECTED") { + // RTC is really connected after a short delay return timeout(() => setUID(resolvedClient.uid), 0); } else if (state === "DISCONNECTED") { setUID(void 0); diff --git a/packages/agora-rtc-react/src/hooks/tracks.ts b/packages/agora-rtc-react/src/hooks/tracks.ts index 315a55bf..2e25edb1 100644 --- a/packages/agora-rtc-react/src/hooks/tracks.ts +++ b/packages/agora-rtc-react/src/hooks/tracks.ts @@ -9,9 +9,10 @@ import { useEffect, useState } from "react"; import { interval, joinDisposers } from "../utils"; import { listen } from "../listen"; import { useRTCClient } from "./context"; +import { useIsConnected } from "./client"; /** - * Subscribe and get remote user video track. + * Auto-subscribe and get remote user video track. * Unsubscribe track on unmount. */ export function useRemoteUserTrack( @@ -19,7 +20,7 @@ export function useRemoteUserTrack( mediaType: "video", ): IRemoteVideoTrack | undefined; /** - * Subscribe and get remote user audio track. + * Auto-subscribe and get remote user audio track. * Unsubscribe track on unmount. */ export function useRemoteUserTrack( @@ -33,9 +34,10 @@ export function useRemoteUserTrack( const client = useRTCClient(); const trackName = mediaType === "audio" ? "audioTrack" : "videoTrack"; const [track, setTrack] = useState(user && user[trackName]); + const isConnected = useIsConnected(); useEffect(() => { - if (!user) return; + if (!user || !isConnected) return; let isUnmounted = false; @@ -63,14 +65,14 @@ export function useRemoteUserTrack( const unsubscribe = (user: IAgoraRTCRemoteUser, mediaType: "audio" | "video"): Promise => client.unsubscribe(user, mediaType).catch(console.error); - if (!user[trackName] && user[hasTrack]) { + if (!user[trackName] && user[hasTrack] && client.remoteUsers.includes(user)) { subscribe(user, mediaType); } return joinDisposers([ () => { isUnmounted = true; - if (user[trackName]) { + if (user[trackName] && client.remoteUsers.includes(user)) { unsubscribe(user, mediaType); } }, @@ -86,7 +88,7 @@ export function useRemoteUserTrack( } }), ]); - }, [client, user, mediaType, trackName]); + }, [isConnected, client, user, mediaType, trackName]); return track; }