diff --git a/mobile/packages/expo-two-way-audio/src/hooks.ts b/mobile/packages/expo-two-way-audio/src/hooks.ts index 8f8bf8c8d..03c2468ab 100644 --- a/mobile/packages/expo-two-way-audio/src/hooks.ts +++ b/mobile/packages/expo-two-way-audio/src/hooks.ts @@ -12,15 +12,21 @@ export const useMicrophonePermissions = createPermissionHook({ requestMethod: requestMicrophonePermissionsAsync }) -export function useIsRecording() { - const subscribe = (cb: () => void) => { - const sub = addExpoTwoWayAudioEventListener('onRecordingChange', cb) - return () => sub.remove() - } - const getSnapshot = () => isRecording() - const getServerSnapshot = () => false +// Why: useSyncExternalStore resubscribes when these identities change; keep +// the native recording listener stable across component re-renders. +const subscribeToRecordingChanges = (cb: () => void) => { + const sub = addExpoTwoWayAudioEventListener('onRecordingChange', cb) + return () => sub.remove() +} +const getRecordingSnapshot = () => isRecording() +const getServerRecordingSnapshot = () => false - return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) +export function useIsRecording() { + return useSyncExternalStore( + subscribeToRecordingChanges, + getRecordingSnapshot, + getServerRecordingSnapshot + ) } export function useExpoTwoWayAudioEventListener(