React-native-reanimated: App freezes when calling `scrollTo` from `useAnimatedScrollHandler`

Created on 11 Aug 2020  路  16Comments  路  Source: software-mansion/react-native-reanimated

Description

I have two ScrollViews, one of them with a useAnimatedScrollHandler. When this handler's onScroll event is fired, the worklet calls the new function scrollTo from #936 on the other ScrollView.

This seems to freeze the whole app, at least in the simulator. The UI becomes unresponsive. Might be an infinite loop of the native thread.

Steps To Reproduce

  1. Call scrollTo inside onScroll of a useAnimatedScrollHandler. This is the scenario of #949, which should be possible with #936.

Expected behavior

Both ScrollViews should scroll.

Actual behavior

App seems to freeze.

Snack or minimal code example

import Animated, {
  useAnimatedScrollHandler,
  scrollTo,
  useAnimatedRef,
} from 'react-native-reanimated';
import {View, Text, SafeAreaView} from 'react-native';
import React, { useRef, useState } from 'react';

export default function OnScrollScrollTo(props) {

  const svStyle = {
    height: 70,
    flexGrow: 0,
  };

  const itemStyle = { padding: 20 };

  const [state, setState] = useState(0);
  const sv1 = useAnimatedRef();
  const sv2 = useRef();
  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (event) => {
      scrollTo(sv1, event.contentOffset.x * 0.5, 0, true);         // if this is commented out, the app runs fine
      setState(event.contentOffset.x);
    },
  });

  return (
    <>
      <SafeAreaView></SafeAreaView>
      <Text>{state}</Text>
      <View
        style={{
          flex: 1,
          flexDirection: 'column',
          justifyContent: 'flex-start',
        }}>
        <Animated.ScrollView ref={sv1} style={svStyle} horizontal>
          {[...Array(10).keys()].map(x => <Text key={x} style={itemStyle}>{x}</Text>)}
        </Animated.ScrollView>
        <Animated.ScrollView ref={sv2} style={svStyle} horizontal
                             onScroll={scrollHandler} scrollEventThrottle={1}
                             >
          {[...Array(20).keys()].map(x => <Text key={x} style={itemStyle}>{x}</Text>)}
        </Animated.ScrollView>
      </View>
      <SafeAreaView></SafeAreaView>
    </>
  );
}

Package versions

  • React: 16.13.1
  • React Native: 0.63.1
  • React Native Reanimated: 2.0.0-alpha.5
馃彔 Reanimated2 馃悶 Bug

Most helpful comment

I don't think that creating a new issue is needed. I'll forward it to the team.

All 16 comments

Hi @yolpsoftware is this still ongoing issue after #1119 ?

@oguzhanali glad to test it with alpha 6 as soon as it is out.

@yolpsoftware What timing! 馃槃 alpha.6 just came out.

@yolpsoftware I tried your repro code with react: 16.13.1, react-native: 0.63.2 and new alpha 6 on Android. There is a typescript error for scrollTo function's ref element when use it without type declaration. I declared its type as Animated.ScrollView, type error is gone but scrollTo is not working again. There is no freezing or error.

I took a look it again, then realized that I forget to add babel plugin for reanimated2. After adding it worked for iOS just fine, both scrollViews scroll synchronously. But on Android app is still freezing as @yolpsoftware said for alpha 5 version.

Glad it works on iOS. Going to test it too, as soon as I have time.

@jakub-gonet Apparently, this also affects Android, but #1119 was only fixed on iOS. Should we open a new ticket?

I don't think that creating a new issue is needed. I'll forward it to the team.

I am getting this issue trying to use scrollTo on Android. Works fine on iOS.
Edit: I'm using '2.0.0-alpha.7' version.

Screenshot 2020-10-01 at 11 07 44

@DrChrispoper could you post a component's code?

I have two Flatlists, one vertical and one horizontal. And trying to scroll the other when you scroll one.

  const detailsRef: any = useAnimatedRef();
  const picsRef: any = useAnimatedRef();
  const scrollHandlerPics = useAnimatedScrollHandler({
    onScroll: event => {
      const offset = (event.contentOffset.x / PICS_WIDTH) * itemHeight;
      scrollTo(detailsRef, 0, offset, false);
    },
  });

    <FlatList
      contentContainerStyle={{
        paddingTop: ScreenWidth / 2 - PICS_WIDTH / 2,
      }}
      data={profiles}
      renderItem={({ item }) => (
        <ProfilePicture
          ...
        />
      )}
      keyExtractor={item => item.id}
      extraData={selectedId}
      snapToAlignment="start"
      snapToInterval={PICS_WIDTH}
      decelerationRate="fast"
      style={{ height: 100 }}
      horizontal
      renderScrollComponent={props => (
        <Animated.ScrollView {...props} onScroll={scrollHandlerPics} />
      )}
      ref={picsRef}
      showsHorizontalScrollIndicator={false}
      scrollEventThrottle={1}
      initialNumToRender={profiles.length}
      getItemLayout={(data, index) => ({ length: PICS_WIDTH, offset: PICS_WIDTH * index, index })}
    />
  const scrollHandlerDetails = useAnimatedScrollHandler({
    onScroll: event => {
      const offset = (event.contentOffset.y / itemHeight) * PICS_WIDTH;
      scrollTo(picsRef, offset, 0, false);
    },
  });

  <FlatList
    data={profiles}
    renderItem={({ item }) => <ProfileDetails ... />}
    keyExtractor={item => item.id}
    snapToAlignment="start"
    snapToInterval={itemHeight}
    decelerationRate="fast"
    renderScrollComponent={props => (
      <Animated.ScrollView {...props} onScroll={scrollHandlerDetails} />
    )}
    showsVerticalScrollIndicator={false}
    scrollEventThrottle={1}
    ref={detailsRef}
    bounces={false}
    initialNumToRender={profiles.length}
    getItemLayout={(data, index) => ({ length: itemHeight, offset: itemHeight * index, index })}
  />

Unfortunately I couldn't reproduce this. Your case is strange as scroll type is explicitly checked that should not be an issue. You might want to clean and rebuild the project previously reinstalling node modules.

I tried to do a full clean and rebuild but I still have the issue.
@karol-bisztyga I've sent you an invite to the repo with the full code. It's nothing important but I want to keep it private for now.
The code is in the branch HorizontalScrollFix
If anybody wants to test, I can send an invite.

@DrChrispoper I can see you're using Expo and alpha.7, but the only supported version right now, according to the expo documentation is

[email protected]

@terrysahaidak That could be the issue I guess. I will keep an eye out when Expo updates its support for alpha.7 because there is a fix in that version for horizontal scrolling.

How to call useAnimatedScrollHandleras a function. Example -

const onPostScroll = useAnimatedScrollHandler({ onScroll: (event) => { postImageParallax.value = event.contentOffset.y; }, });

To be used in Swiper(react-native-swiper) component -
<Swiper onScroll={(event) => { ///..... onPostScroll; <--This is a varaiable, How to call this as a function? }}>

I want to call the onPostScroll as a function.

@dhirajanand014 the way I see it what's passed to uash is an object that contains multiple functions(or at least is able to contain). If it's limited to just one: onScroll like in your example, why don't you extract that function and just pass it to the Swiper? I don't really know the whole context of what you're up to so this is just out-of-my-head-first-thought-guessing:

const fun = (event) => { 'worklet';postImageParallax.value = event.contentOffset.y; }
// ...
const onPostScroll = useAnimatedScrollHandler({ onScroll: fun, });
// ...
<Swiper onScroll={fun}>
Was this page helpful?
0 / 5 - 0 ratings