From ca53816aaa62be7d10409b2175fbea541a303acc Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 30 May 2026 11:26:42 -0700 Subject: [PATCH] fix: stabilize audio recording store subscription (#3524) --- .../packages/expo-two-way-audio/src/hooks.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) 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(