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

Fix attaching a scroll event if the scrollable component is not the root view #3988

Merged
merged 1 commit into from Jan 21, 2023

Conversation

graszka22
Copy link
Member

@graszka22 graszka22 commented Jan 21, 2023

Summary

Fixes #3873
getScrollableNode() works not only on FlashLists, but also on RN scrollable components (ScrollView, Flatlist). It's brought back from there

Test plan

@tomekzaw tomekzaw changed the title Fix attaching a scroll event if the scrollable component is not the r… Fix attaching a scroll event if the scrollable component is not the root view Jan 21, 2023
Copy link
Member

@tomekzaw tomekzaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@piaskowyk piaskowyk merged commit 4eee6dd into main Jan 21, 2023
@piaskowyk piaskowyk deleted the @graszka22/fix-attach-native-event branch January 21, 2023 09:47
tomekzaw added a commit that referenced this pull request 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 pull request Jun 5, 2023
…oot view (software-mansion#3988)

<!-- Thanks for submitting a pull request! We appreciate you spending
the time to work on these changes. Please follow the template so that
the reviewers can easily understand what the code changes affect. -->

## Summary

Fixes software-mansion#3873
`getScrollableNode()` works not only on FlashLists, but also on RN
scrollable components (ScrollView, Flatlist). It's brought back from
[there](software-mansion@5829e95#diff-fdad18d3281131f92aa76c0969f84d27f2314251842763fedbc756df07b1eab7L234)


## Test plan

<!-- Provide a minimal but complete code snippet that can be used to
test out this change along with instructions how to run it and a
description of the expected behavior. -->
- tested on the repro from the issue
(https://github.com/diogoquintas/reanimated-scroll-issue)
- tested on several examples from the example app (examples related to
scroll events and events in general for example chat heads)
- tested on FlashList
fluiddot pushed a commit to wordpress-mobile/react-native-reanimated that referenced this pull request 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
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot attach native event on animated component
3 participants