react-native-reanimated-carousel icon indicating copy to clipboard operation
react-native-reanimated-carousel copied to clipboard

Gesture error when applying pagination

Open bil-lekid opened this issue 1 year ago • 1 comments

Describe the bug I copied the parallax horizontal code. It doesn't work but when I removed the pagination the carousel works. And I want to use the pagination

To Reproduce Steps to reproduce the behavior:

  1. Copy the code
import * as React from "react";
import { Dimensions, Text, View } from "react-native";
import { useSharedValue } from "react-native-reanimated";
import Carousel, {
  ICarouselInstance,
  Pagination,
} from "react-native-reanimated-carousel";

const data = [...new Array(6).keys()];
const width = Dimensions.get("window").width;

function App() {
  const ref = React.useRef<ICarouselInstance>(null);
  const progress = useSharedValue<number>(0);
  
  const onPressPagination = (index: number) => {
    ref.current?.scrollTo({
      count: index - progress.value,
      animated: true,
    });
  };

  return (
    <View style={{ flex: 1 }}>
      <Carousel
        ref={ref}
        width={width}
        height={width / 2}
        data={data}
        onProgressChange={progress}
        renderItem={({ index }) => (
          <View
            style={{
              flex: 1,
              borderWidth: 1,
              justifyContent: "center",
            }}
          >
            <Text style={{ textAlign: "center", fontSize: 30 }}>{index}</Text>
          </View>
        )}
      />
      <Pagination.Basic
        progress={progress}
        data={data}
        dotStyle={{ backgroundColor: "rgba(0,0,0,0.2)", borderRadius: 50 }}
        containerStyle={{ gap: 5, marginTop: 10 }}
        onPress={onPressPagination}
      />
    </View>
  );
}

export default App;
  1. It will show this error
Error: NativeViewGestureHandler must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/installation for more details.

This error is located at:
    in NativeViewGestureHandler (created by RNGestureHandlerButton)
    in RNGestureHandlerButton (created by BaseButton)
    in BaseButton (created by GenericTouchable)
    in GenericTouchable
    in Unknown (created by Basic)
    in RCTView (created by View)
    in View (created by Basic)
    in Basic (created by App)
    in RCTView (created by View)
    in View (created by App)
    in App (created by AuthIndex)
    in RCTView (created by View)
    in View (created by ThemedView)
    in ThemedView (created by AuthIndex)
    in AuthIndex
    in Unknown (created by Route(index))
    in Suspense (created by Route(index))
    in Route (created by Route(index))
    in Route(index) (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by SceneView)
    in RCTView (created by View)
    in View (created by DebugContainer)
    in DebugContainer (created by MaybeNestedStack)
    in MaybeNestedStack (created by SceneView)
    in RCTView (created by View)
    in View (created by SceneView)
    in RNSScreen (created by Animated(Anonymous))
    in Animated(Anonymous) (created by InnerScreen)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by InnerScreen)
    in InnerScreen (created by Screen)
    in Screen (created by SceneView)
    in SceneView (created by NativeStackViewInner)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by ScreenStack)
    in RNSScreenStack (created by ScreenStack)
    in ScreenStack (created by NativeStackViewInner)
    in NativeStackViewInner (created by NativeStackView)
    in RCTView (created by View)
    in View (created by SafeAreaProviderCompat)
    in SafeAreaProviderCompat (created by NativeStackView)
    in NativeStackView (created by NativeStackNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by NativeStackNavigator)
    in NativeStackNavigator
    in Unknown (created by AuthLayout)
    in RNCSafeAreaView
    in Unknown (created by AuthLayout)
    in AuthLayout
    in Unknown (created by Route(auth))
    in Suspense (created by Route(auth))
    in Route (created by Route(auth))
    in Route(auth) (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by SceneView)
    in RCTView (created by View)
    in View (created by DebugContainer)
    in DebugContainer (created by MaybeNestedStack)
    in MaybeNestedStack (created by SceneView)
    in RCTView (created by View)
    in View (created by SceneView)
    in RNSScreen (created by Animated(Anonymous))
    in Animated(Anonymous) (created by InnerScreen)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by InnerScreen)
    in InnerScreen (created by Screen)
    in Screen (created by SceneView)
    in SceneView (created by NativeStackViewInner)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by ScreenStack)
    in RNSScreenStack (created by ScreenStack)
    in ScreenStack (created by NativeStackViewInner)
    in NativeStackViewInner (created by NativeStackView)
    in RCTView (created by View)
    in View (created by SafeAreaProviderCompat)
    in SafeAreaProviderCompat (created by NativeStackView)
    in NativeStackView (created by NativeStackNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by NativeStackNavigator)
    in NativeStackNavigator
    in Unknown (created by RootLayout)
    in ThemeProvider (created by RootLayout)
    in QueryClientProvider (created by RootLayout)
    in RootLayout
    in Unknown (created by Route())
    in Suspense (created by Route())
    in Route (created by Route())
    in Route() (created by ContextNavigator)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by wrapper)
    in wrapper (created by ContextNavigator)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by ContextNavigator)
    in ContextNavigator (created by ExpoRoot)
    in ExpoRoot (created by App)
    in App (created by ErrorOverlay)
    in ErrorToastContainer (created by ErrorOverlay)
    in ErrorOverlay (created by withDevTools(ErrorOverlay))
    in withDevTools(ErrorOverlay)
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in main(RootComponent), js engine: hermes
  1. Delete the <Pagination.Basic />
  2. Carousel works but pagination gone

Expected behavior Both Carousel and Pagination working

Screenshots If applicable, add screenshots to help explain your problem.

Versions (please complete the following information): "expo": "~51.0.28", "react": "18.2.0", "react-native": "0.74.5", "react-native-gesture-handler": "~2.16.1", "react-native-reanimated": "~3.10.1", "react-native-reanimated-carousel": "4.0.0-alpha.12",

Smartphone (please complete the following information):

  • Device: Samsung A71 [e.g. iPhone6]
  • OS: Android 13 [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context Add any other context about the problem here.

bil-lekid avatar Sep 10 '24 06:09 bil-lekid

Hey @bil-lekid! I'm here to help you with any bugs, questions, or contributions while you wait for a human maintainer. Let's get to the bottom of this together!

To resolve the "NativeViewGestureHandler must be used as a descendant of GestureHandlerRootView" error when using pagination with the react-native-reanimated-carousel, you need to ensure that the Carousel component is wrapped in a GestureHandlerRootView. This is necessary for the gesture handlers to work correctly.

Here's how you can modify your code to include the GestureHandlerRootView:

import * as React from "react";
import { View } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { useSharedValue } from "react-native-reanimated";
import Carousel, {
  ICarouselInstance,
  Pagination,
} from "react-native-reanimated-carousel";

import { SBItem } from "../../components/SBItem";
import SButton from "../../components/SButton";
import { ElementsText, window } from "../../constants";

const PAGE_WIDTH = window.width;
const colors = [
  "#26292E",
  "#899F9C",
  "#B3C680",
  "#5C6265",
  "#F5D399",
  "#F1F1F1",
];

function Index() {
  const [isVertical, setIsVertical] = React.useState(false);
  const [autoPlay, setAutoPlay] = React.useState(false);
  const [pagingEnabled, setPagingEnabled] = React.useState<boolean>(true);
  const [snapEnabled, setSnapEnabled] = React.useState<boolean>(true);
  const progress = useSharedValue<number>(0);
  const baseOptions = isVertical
    ? ({
        vertical: true,
        width: PAGE_WIDTH * 0.86,
        height: PAGE_WIDTH * 0.6,
      } as const)
    : ({
        vertical: false,
        width: PAGE_WIDTH,
        height: PAGE_WIDTH * 0.6,
      } as const);

  const ref = React.useRef<ICarouselInstance>(null);

  const onPressPagination = (index: number) => {
    ref.current?.scrollTo({
      count: index - progress.value,
      animated: true,
    });
  };

  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <View
        style={{
          alignItems: "center",
        }}
      >
        <Carousel
          ref={ref}
          {...baseOptions}
          style={{
            width: PAGE_WIDTH,
          }}
          loop
          pagingEnabled={pagingEnabled}
          snapEnabled={snapEnabled}
          autoPlay={autoPlay}
          autoPlayInterval={1500}
          onProgressChange={progress}
          mode="parallax"
          modeConfig={{
            parallaxScrollingScale: 0.9,
            parallaxScrollingOffset: 50,
          }}
          data={colors}
          renderItem={({ index }) => <SBItem index={index} />}
        />

        <Pagination.Basic
          progress={progress}
          data={colors}
          dotStyle={{ backgroundColor: "rgba(0,0,0,0.2)" }}
          containerStyle={{ gap: 5, marginBottom: 10 }}
          onPress={onPressPagination}
        />

        <Pagination.Basic<{ color: string }>
          progress={progress}
          data={colors.map((color) => ({ color }))}
          dotStyle={{
            width: 25,
            height: 4,
            backgroundColor: "rgba(0,0,0,0.2)",
          }}
          activeDotStyle={{
            overflow: "hidden",
          }}
          containerStyle={[
            isVertical
              ? {
                  position: "absolute",
                  width: 25,
                  right: 5,
                  top: 40,
                }
              : undefined,
            {
              gap: 10,
              marginBottom: 10,
            },
          ]}
          horizontal={!isVertical}
          onPress={onPressPagination}
        />

        <Pagination.Basic<{ color: string }>
          progress={progress}
          data={colors.map((color) => ({ color }))}
          size={20}
          dotStyle={{
            borderRadius: 100,
            backgroundColor: "rgba(0,0,0,0.2)",
          }}
          activeDotStyle={{
            borderRadius: 100,
            overflow: "hidden",
          }}
          containerStyle={[
            isVertical
              ? {
                  position: "absolute",
                  width: 20,
                  right: 5,
                  top: 40,
                }
              : undefined,
            {
              gap: 5,
              marginBottom: 10,
            },
          ]}
          horizontal={!isVertical}
          onPress={onPressPagination}
        />

        <Pagination.Basic<{ color: string }>
          progress={progress}
          data={colors.map((color) => ({ color }))}
          size={20}
          dotStyle={{
            borderRadius: 100,
            backgroundColor: "rgba(0,0,0,0.2)",
          }}
          activeDotStyle={{
            borderRadius: 100,
            overflow: "hidden",
          }}
          containerStyle={[
            isVertical
              ? {
                  position: "absolute",
                  width: 20,
                  right: 5,
                  top: 40,
                }
              : undefined,
          ]}
          horizontal={!isVertical}
          renderItem={(item) => (
            <View
              style={{
                backgroundColor: item.color,
                flex: 1,
              }}
            />
          )}
          onPress={onPressPagination}
        />

        <SButton
          onPress={() => setAutoPlay(!autoPlay)}
        >{`${ElementsText.AUTOPLAY}:${autoPlay}`}</SButton>
        <SButton
          onPress={() => {
            setIsVertical(!isVertical);
          }}
        >
          {isVertical ? "Set horizontal" : "Set Vertical"}
        </SButton>
        <SButton
          onPress={() => {
            setPagingEnabled(!pagingEnabled);
          }}
        >
          {`pagingEnabled:${pagingEnabled}`}
        </SButton>
        <SButton
          onPress={() => {
            setSnapEnabled(!snapEnabled);
          }}
        >
          {`snapEnabled:${snapEnabled}`}
        </SButton>
      </View>
    </GestureHandlerRootView>
  );
}

export default Index;

Make sure that the GestureHandlerRootView is the top-level component or at least wraps the Carousel component in your component tree. This should resolve the error [1].

To continue talking to Dosu, mention @dosu.

dosubot[bot] avatar Sep 10 '24 06:09 dosubot[bot]

This bug seems to be fixed for me in v4.0.0-canary.17.

I think it may have been fixed with v4.0.0-canary.15.

The error also went away for me in 4.0.0-alpha.12 if I wrapped both the carousel and pagination components in another GestureHandlerRootView.

The docs for react-native-gesture-handler don't seem to mention anything about nesting multiple GestureHandlerRootView components (the Carousel component includes it). But since they do recommend including it in open-source libraries this way, I assume it is probably safe to do so.

traviswimer avatar Nov 23 '24 16:11 traviswimer

Hi, @bil-lekid. I'm Dosu, and I'm helping the react-native-reanimated-carousel team manage their backlog. I'm marking this issue as stale.

Issue Summary:

  • You reported a gesture error when using pagination with the carousel, which disappears when pagination is removed.
  • The error message suggested using NativeViewGestureHandler within a GestureHandlerRootView.
  • A solution was provided to wrap the Carousel component in a GestureHandlerRootView.
  • It was noted that the issue seems fixed in v4.0.0-canary.17, and wrapping both components in GestureHandlerRootView resolved it in 4.0.0-alpha.12.

Next Steps:

  • Please confirm if this issue is still relevant with the latest version of the react-native-reanimated-carousel repository. If so, you can keep the discussion open by commenting here.
  • If there is no further activity, this issue will be automatically closed in 7 days.

Thank you for your understanding and contribution!

dosubot[bot] avatar Feb 22 '25 16:02 dosubot[bot]