Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scrollTo not working with FlashList #4376

Closed
QOAL opened this issue Apr 19, 2023 · 4 comments · Fixed by #4384
Closed

scrollTo not working with FlashList #4376

QOAL opened this issue Apr 19, 2023 · 4 comments · Fixed by #4384
Labels
Needs review Issue is ready to be reviewed by a maintainer Platform: Android This issue is specific to Android Repro provided A reproduction with a snippet of code, snack or repo is provided

Comments

@QOAL
Copy link

QOAL commented Apr 19, 2023

Description

I've seen there's been previous work done to accommodate FlashList with Reanimated, but I'm still suffering from an issue when using it myself.

Using scrollTo on an animated reference of a FlashList does nothing, but works fine with a standard FlatList.

The provided test case is quite similar to actual usage in my app, other than I actually use a gesture to set the position.

Steps to reproduce

Run the provided repository and press the New Pos button, or see App.js

Snack or a link to a repository

https://github.com/QOAL/rnflrepro

Reanimated version

3.0.2

React Native version

0.71.7

Platforms

Android

JavaScript runtime

Hermes

Workflow

React Native (without Expo)

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

Real device

Device model

Realme 7 (Global)

Acknowledgements

Yes

@QOAL QOAL added the Needs review Issue is ready to be reviewed by a maintainer label Apr 19, 2023
@github-actions github-actions bot added Repro provided A reproduction with a snippet of code, snack or repo is provided Platform: Android This issue is specific to Android labels Apr 19, 2023
@tomekzaw
Copy link
Member

Hey @QOAL, thanks for reporting this issue and for the repro, I will take a look on it.

@tomekzaw
Copy link
Member

Hey @QOAL, based on the repro you have provided I was able to successfully reproduce the issue, find out what's wrong and come up with a fix:

tag.value = getTagValueFunction(component);

-tag.value = getTagValueFunction(component);
+tag.value = getTagValueFunction(component.getScrollableNode ? component.getScrollableNode() : component);

I will submit a PR with this fix soon. Thanks again!

@QOAL
Copy link
Author

QOAL commented Apr 19, 2023

Brilliant! Thank you so much for investigating. I appreciate it.

@tomekzaw
Copy link
Member

Here's the PR: #4384

tomekzaw added a commit that referenced this issue Apr 21, 2023
## 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:

<details>
<summary>App.tsx</summary>

```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<FlashList<Item>>();

  const scrollFromJS = () => {
    console.log(_WORKLET);
    aref.current?.scrollToOffset({offset: getRandomOffset(), animated});
  };

  const scrollFromUI = () => {
    runOnUI(() => {
      'worklet';
      console.log(_WORKLET);
      scrollTo(aref, 0, getRandomOffset(), animated);
    })();
  };

  return (
    <>
      <View style={styles.buttons}>
        <Switch
          value={animated}
          onValueChange={setAnimated}
          style={styles.switch}
        />
        <Button onPress={scrollFromJS} title="Scroll from JS" />
        <Button onPress={scrollFromUI} title="Scroll from UI" />
      </View>
      <AnimatedFlashList
        // @ts-ignore createAnimatedComponent seems to break generic types
        ref={aref}
        data={DATA}
        // @ts-ignore createAnimatedComponent seems to break generic types
        renderItem={({item}: {item: Item}) => (
          <Text key={item.label} style={styles.text}>
            {item.label}
          </Text>
        )}
        estimatedItemSize={200}
      />
    </>
  );
}

const styles = StyleSheet.create({
  switch: {
    marginBottom: 10,
  },
  buttons: {
    marginTop: 80,
    marginBottom: 40,
    alignItems: 'center',
  },
  text: {
    fontSize: 50,
    textAlign: 'center',
  },
});
```

</details>

Before:

<img
src="https://user-images.githubusercontent.com/20516055/233323545-427cc3d4-4479-4b02-a24b-5a3039fb3105.png"
width="300" />

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 <kbd>r</kbd> to reload the app and check
again.
fluiddot pushed a commit to wordpress-mobile/react-native-reanimated that referenced this issue Jun 5, 2023
## Summary

Fixes software-mansion#4376. Analogous to software-mansion#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:

<details>
<summary>App.tsx</summary>

```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<FlashList<Item>>();

  const scrollFromJS = () => {
    console.log(_WORKLET);
    aref.current?.scrollToOffset({offset: getRandomOffset(), animated});
  };

  const scrollFromUI = () => {
    runOnUI(() => {
      'worklet';
      console.log(_WORKLET);
      scrollTo(aref, 0, getRandomOffset(), animated);
    })();
  };

  return (
    <>
      <View style={styles.buttons}>
        <Switch
          value={animated}
          onValueChange={setAnimated}
          style={styles.switch}
        />
        <Button onPress={scrollFromJS} title="Scroll from JS" />
        <Button onPress={scrollFromUI} title="Scroll from UI" />
      </View>
      <AnimatedFlashList
        // @ts-ignore createAnimatedComponent seems to break generic types
        ref={aref}
        data={DATA}
        // @ts-ignore createAnimatedComponent seems to break generic types
        renderItem={({item}: {item: Item}) => (
          <Text key={item.label} style={styles.text}>
            {item.label}
          </Text>
        )}
        estimatedItemSize={200}
      />
    </>
  );
}

const styles = StyleSheet.create({
  switch: {
    marginBottom: 10,
  },
  buttons: {
    marginTop: 80,
    marginBottom: 40,
    alignItems: 'center',
  },
  text: {
    fontSize: 50,
    textAlign: 'center',
  },
});
```

</details>

Before:

<img
src="https://user-images.githubusercontent.com/20516055/233323545-427cc3d4-4479-4b02-a24b-5a3039fb3105.png"
width="300" />

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 <kbd>r</kbd> to reload the app and check
again.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs review Issue is ready to be reviewed by a maintainer Platform: Android This issue is specific to Android Repro provided A reproduction with a snippet of code, snack or repo is provided
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants