31d100bb14
guard against a null view tag when keyboard-controller's useExtraContentPadding flushes its deferred scrollTo. the rAF callback can fire after the ScrollView detaches (navigating away, list re-creating its scroll component), at which point scrollViewRef() is null. on the old arch reanimated's scrollTo passes that null to the native _scrollToPaper HostFunction, which throws "Value is null, expected a number". re-check the ref inside the rAF before scrolling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
58 lines
2.5 KiB
Diff
58 lines
2.5 KiB
Diff
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(
|