diff --git a/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts b/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts index 0f6d7c67a307885310ab184fdf9e7a5c7b296825..1a01093e7909973cef5268f999158df389e77634 100644 --- a/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts +++ b/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts @@ -1,8 +1,6 @@ import { useCallback } from "react"; -import { Platform } from "react-native"; import { scrollTo, useAnimatedReaction } from "react-native-reanimated"; -import { IS_FABRIC } from "../../../architecture"; import { isScrollAtEnd, shouldShiftContent } from "../useChatKeyboard/helpers"; import type { KeyboardLiftBehavior } from "../useChatKeyboard/types"; @@ -52,7 +50,6 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { scroll, layout, size, - contentOffsetY, inverted, keyboardLiftBehavior, freeze, @@ -62,20 +59,23 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { (target: number) => { "worklet"; - if (contentOffsetY && IS_FABRIC) { - // eslint-disable-next-line react-compiler/react-compiler - contentOffsetY.value = target; - } else if (Platform.OS === "android") { - // Defer scrollTo so the animatedProps inset commit lands first; - // otherwise the native ScrollView clamps to the old range. - requestAnimationFrame(() => { - scrollTo(scrollViewRef, 0, target, false); - }); - } else { + // Always defer scrollTo so the animatedProps inset commit lands first; + // otherwise the native ScrollView clamps contentOffset to the old + // contentInset range (iOS Fabric) or the old contentInsetBottom (Android). + requestAnimationFrame(() => { + // The ScrollView can detach between scheduling this frame and now (e.g. + // navigating away from the screen, or the list re-creating its scroll + // component). Once detached, scrollViewRef() resolves to null, and on + // Paper reanimated's scrollTo hands that null to the native + // _scrollToPaper HostFunction, which throws "Value is null, expected a + // number". Re-check the ref now that the frame has arrived. + if (scrollViewRef() == null) { + return; + } scrollTo(scrollViewRef, 0, target, false); - } + }); }, - [scrollViewRef, contentOffsetY], + [scrollViewRef], ); useAnimatedReaction(