Skip to content

Commit cdbf1e9

Browse files
janicduplessisosdnk
authored andcommitted
feat: handle animated component wrappers in useScrollToTop (facebook#81)
1 parent 56a2ee9 commit cdbf1e9

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

packages/native/src/useScrollToTop.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,31 @@ type ScrollableView =
99
| { scrollToOffset(options: ScrollOptions): void }
1010
| { scrollResponderScrollTo(options: ScrollOptions): void };
1111

12-
export default function useScrollToTop(ref: React.RefObject<ScrollableView>) {
12+
type MaybeScrollableWrapperView =
13+
| ScrollableView
14+
| { getScrollResponder: () => ScrollableView }
15+
| { getNode: () => ScrollableView };
16+
17+
function getNodeFromRef(
18+
ref: React.RefObject<MaybeScrollableWrapperView>
19+
): ScrollableView | null {
20+
if (ref.current === null) {
21+
return null;
22+
}
23+
24+
// Support weird animated containers and Animated components.
25+
if ('getScrollResponder' in ref.current) {
26+
return ref.current.getScrollResponder();
27+
} else if ('getNode' in ref.current) {
28+
return ref.current.getNode();
29+
} else {
30+
return ref.current;
31+
}
32+
}
33+
34+
export default function useScrollToTop(
35+
ref: React.RefObject<MaybeScrollableWrapperView>
36+
) {
1337
const navigation = useNavigation();
1438

1539
React.useEffect(
@@ -23,7 +47,7 @@ export default function useScrollToTop(ref: React.RefObject<ScrollableView>) {
2347
// Run the operation in the next frame so we're sure all listeners have been run
2448
// This is necessary to know if preventDefault() has been called
2549
requestAnimationFrame(() => {
26-
const scrollable = ref.current;
50+
const scrollable = getNodeFromRef(ref);
2751

2852
if (isFocused && !e.defaultPrevented && scrollable) {
2953
// When user taps on already focused tab, scroll to top

0 commit comments

Comments
 (0)