From 835a716eaf2b3a9f2ef4d2058168faaf7818d650 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 11 Nov 2025 02:02:13 +0200 Subject: [PATCH] Try and guard against play/pause function being called after player is destroyed (#9364) * try and guard play/pause against unmount * add try/catch to avoid fatal crashes --- src/screens/VideoFeed/index.tsx | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/screens/VideoFeed/index.tsx b/src/screens/VideoFeed/index.tsx index 08fd6a9aaf..98f0f3d477 100644 --- a/src/screens/VideoFeed/index.tsx +++ b/src/screens/VideoFeed/index.tsx @@ -57,6 +57,7 @@ import { import {sanitizeDisplayName} from '#/lib/strings/display-names' import {cleanError} from '#/lib/strings/errors' import {sanitizeHandle} from '#/lib/strings/handles' +import {logger} from '#/logger' import {isAndroid} from '#/platform/detection' import {useA11y} from '#/state/a11y' import { @@ -1044,16 +1045,29 @@ function PlayPauseTapArea({ const {isPlaying} = useEvent(player, 'playingChange', { isPlaying: player.playing, }) + const isMounted = useRef(false) - const togglePlayPause = () => { - if (!player) return - doubleTapRef.current = null - if (player.playing) { - player.pause() - } else { - player.play() + useEffect(() => { + isMounted.current = true + return () => { + isMounted.current = false } - } + }, []) + + const togglePlayPause = useNonReactiveCallback(() => { + // gets called after a timeout, so guard against being called after unmount -sfn + if (!player || !isMounted.current) return + doubleTapRef.current = null + try { + if (player.playing) { + player.pause() + } else { + player.play() + } + } catch (err) { + logger.error('Could not toggle play/pause', {safeMessage: err}) + } + }) const onPress = () => { if (doubleTapRef.current) {