Skip to content

Android error with using react-native-reanimated, "The specified child already has a parent. You must call removeView() on the child's parent first" #1571

Open
@xrustic2020

Description

@xrustic2020

Current behavior

We use latest versions of the FlashList package - v1.7.5 and tried downgraded version 1.7.2, but it wasn't help.

We use Animated (reanimated) Flash List in our component. When execute first render our component - all is ok, but when we go to other screen and back to screen with our component - we have error, but it caught only on android platform.

When we use FlatList from react-native - all is ok, problem reproduced only with FlashList, passed to Animated.createAnimatedComponent (from reanimated)

import type { RefObject } from 'react';
import React, { useCallback, useMemo, useRef } from 'react';
import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated';
import { FlashList, type ListRenderItem, type ListRenderItemInfo } from '@shopify/flash-list';
import { StyleSheet, View, type NativeScrollEvent, type NativeSyntheticEvent } from 'react-native';

const AnimatedFlashList = Animated.createAnimatedComponent(FlashList);

type PropsType<T> = React.ComponentPropsWithRef<typeof FlashList<T>> & {
  data: T[];
  isLoop?: boolean;
  width?: number;
  height?: number;
  renderItem: ListRenderItem<T>;
};

..

function Carousel<DataType>(
  props: PropsType<DataType>
) {
  const carouselRef = useRef<FlashList<DataType>>(null);

  const scrollOffset = useSharedValue(0);

  const {
    width = DEVICE_WIDTH,
    height = DEVICE_HEIGHT,
    isLoop = false,
    data,
    ...otherProps
  } = props;

  const gappedData = useMemo(
    () => (isLoop && data.length >= 3 ? [data[data.length - 1], ...data, data[0]] : data),
    [isLoop, data],
  );

  const scrollHandler = useAnimatedScrollHandler(event => {
    scrollOffset.value = event.contentOffset.x;
  });

  const handleMomentumScrollEnd = useCallback(
    (event: NativeSyntheticEvent<NativeScrollEvent>) => {
      if (props.onMomentumScrollEnd instanceof Function) {
        props.onMomentumScrollEnd(event);
      }

      if (!isLoop) return;

      if (
        event.nativeEvent.contentOffset.x === 0 ||
        event.nativeEvent.contentOffset.x >= Math.floor(width * gappedData.length - width)
      ) {
        const nextIndex = event.nativeEvent.contentOffset.x === 0 ? gappedData.length - 2 : 1;

        carouselRef.current?.scrollToIndex({
          animated: false,
          index: nextIndex,
        });
      }
    },
    [carouselRef, gappedData.length, isLoop, props, width],
  );

  const listWrapperStyle = useMemo(
    () =>
      StyleSheet.create({ res: { alignItems: 'center', justifyContent: 'center', width, height } })
        .res,
    [width, height],
  );

  const renderItem = useCallback(
    (info: ListRenderItemInfo<DataType>) => (
      <SomeComponent scrollOffset={scrollOffset}>
    ),
    [props, scrollOffset, width],
  );

  return (
      <AnimatedFlashList
        horizontal
        pagingEnabled
        decelerationRate="fast"
        bounces={false}
        overScrollMode="never"
        initialScrollIndex={props.initialScrollIndex ?? 0}
        scrollEventThrottle={16}
        estimatedItemSize={width}
        showsHorizontalScrollIndicator={false}
        showsVerticalScrollIndicator={false}
        data={gappedData}
        ref={carouselRef}
        onMomentumScrollEnd={handleMomentumScrollEnd}
        onScroll={scrollHandler}
        renderItem={renderItem}
      />
  );
}

Component has been called:

<Carousel
        data={resources}
        renderItem={renderItem}
        extraData={extraData}
        isLoop={isLoop}
        width={width}
        height={height}
      />

Expected behavior

Expected behavior without errors and without application crashes

To Reproduce

We run application on debug or production mode. When components is mounted - we go to other screen, and when we go repeat to first screen (with our component with AnimatedFlashList) - we caught this error:
Image

Platform:

  • iOS
  • Android

Environment

We also tried reproduced this case with downgraded version 1.7.2, but it was not help

"@shopify/flash-list": "1.7.5",
"react-native-reanimated": "3.15.5",
"react-native": "0.75.4",

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions