From 690b887e8d62e5b1d3b969be23654368ff86ac78 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Fri, 21 Apr 2023 17:41:31 +0200 Subject: [PATCH] Fix scrollTo on FlashList (#4384) ## Summary Fixes #4376. Analogous to #3988. Solution: copy the code from `createAnimatedComponent.tsx` to `useAnimatedRef.ts` https://github.com/software-mansion/react-native-reanimated/blob/87fb9c6a1fb6b8c839b65b90ad16f574f45a1294/src/createAnimatedComponent.tsx#L289-L291 Example:
App.tsx ```tsx import Animated, { runOnUI, scrollTo, useAnimatedRef, } from 'react-native-reanimated'; import {Button, StyleSheet, Switch, Text, View} from 'react-native'; import {FlashList} from '@shopify/flash-list'; import React from 'react'; declare const _WORKLET: boolean; const AnimatedFlashList = Animated.createAnimatedComponent(FlashList); interface Item { label: string; } const DATA: Item[] = [...Array(100)].map((_, i) => ({label: String(i)})); function getRandomOffset() { 'worklet'; return Math.random() * 2000; } export default function ScrollToExample() { const [animated, setAnimated] = React.useState(true); const aref = useAnimatedRef>(); const scrollFromJS = () => { console.log(_WORKLET); aref.current?.scrollToOffset({offset: getRandomOffset(), animated}); }; const scrollFromUI = () => { runOnUI(() => { 'worklet'; console.log(_WORKLET); scrollTo(aref, 0, getRandomOffset(), animated); })(); }; return ( <>
Before: Android: https://user-images.githubusercontent.com/20516055/233322746-637fa2a9-0e93-40ac-baa8-c3c3d2449867.mp4 iOS: https://user-images.githubusercontent.com/20516055/233322714-20c03ade-1f15-4d76-8a5e-b4b59ebe8a73.mp4 ## Test plan 1. Install FlashList in Example app with `yarn add @shopify/flash-list && cd ios && pod install` 2. Paste the attached code snippet into App.tsx > **Warning** > It looks like animated refs don't update properly on render. In this case, pressing "Scroll from UI" button after a fast refresh does nothing. Please reload the r to reload the app and check again. --- src/reanimated2/hook/useAnimatedRef.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/reanimated2/hook/useAnimatedRef.ts b/src/reanimated2/hook/useAnimatedRef.ts index bc82c407906..d7739ac396e 100644 --- a/src/reanimated2/hook/useAnimatedRef.ts +++ b/src/reanimated2/hook/useAnimatedRef.ts @@ -9,8 +9,12 @@ import { registerShareableMapping, } from '../shareables'; +interface ComponentRef extends Component { + getScrollableNode?: () => ComponentRef; +} + function getShareableShadowNodeFromComponent( - component: Component + component: ComponentRef ): ShadowNodeWrapper { return getShadowNodeWrapperFromHostInstance(component); } @@ -19,7 +23,7 @@ const getTagValueFunction = global._IS_FABRIC ? getShareableShadowNodeFromComponent : getTag; -export function useAnimatedRef(): RefObjectFunction { +export function useAnimatedRef(): RefObjectFunction { const tag = useSharedValue(-1); const ref = useRef>(); @@ -27,7 +31,11 @@ export function useAnimatedRef(): RefObjectFunction { const fun: RefObjectFunction = >((component) => { // enters when ref is set by attaching to a component if (component) { - tag.value = getTagValueFunction(component); + tag.value = getTagValueFunction( + component.getScrollableNode + ? component.getScrollableNode() + : component + ); fun.current = component; } return tag.value;