[React Native] react-native-gesture 이용하여 스와이프 가능하게 만들기

임소현·2024년 9월 12일
1

React Native

목록 보기
7/17

이번 주제는 react-native-gesture를 이용하여 특정 컴포넌트 행을 스와이프 가능하도록 만들어보려고 한다.

우선적으로, android 버전으로 가능하도록 진행하였고, ios로 실행해보고 ios로 따로 추가해야할 부분이 있으면 추후 수정할 예정이다.

react-native-gesture 라이브러리는 다양한 제스처 기능을 이용할 수 있도록 관련 기능을 제공하는데, 이전에도 드래그 기능을 이용하기 위해 사용해보고자 하였지만, 별의별 에러와 함께 제스처 기능 추가는 미뤄두곤 했었다.

하지만, 이제서야 다시 스와이프 기능을 추가해보고자 한다.

다만, react-native-gesture 라이브러리는 에러 해결 없이는 절대 사용할 수 없다. 반드시 하나 이상의 에러와 마주할 텐데, 나 또한 단지 스와이프 기능만을 추가하려 했을 뿐인데 다양한 종류의 에러가 나타났다.

방법은, 일단 react-native-gesture-handler를 설치해야 한다.

설치 후, babel.config.js 파일에

 plugins: ['react-native-reanimated/plugin'],

위 코드를 추가해줘야 한다. 주의할 점은 저 플러그인이 코드 가장 끝에 추가되어야 한다.

그 후, 앱의 최상단 컴포넌트 (App.tsx) 에 gestureRootView로 감싸주어야 한다.

    <GestureHandlerRootView style={{flex: 1}}>
      <SafeAreaProvider>
        {/* <SafeAreaView style={{flex: 1}}> */}
        <QueryClientProvider client={queryClient}>
          <NavigationContainer>
            <AppStackNavigator />
            <CustomToast />
          </NavigationContainer>
        </QueryClientProvider>
        {/* </SafeAreaView> */}
      </SafeAreaProvider>
    </GestureHandlerRootView>

이런식으로 가장 가장 최상단에 감싸주면 된다.

이렇게 하면 안드로이드는 사용하기 위한 준비를 모두 끝낸 것이다.

하지만 이제부터 시작이다.

gesture 라이브러리는 react native에서 사용해본 라이브러리 중 가장 불안정한 라이브러리로 느껴졌는데, 그 이유는 버전 불안정성이 굉장히 높아 보였다.

실제로, 스와이프 기능에 필요한 Swipeable 역시 벌써 세 개의 다른 버전이 있었고, 이 세 개의 버전은 모두 조금씩 기능들이 달랐다.

이것 외에도 ndk 관련 버전이 안맞는다는 에러도 종종 보일 수 있다.

 ERROR  Warning: TypeError: Cannot read property 'makeMutable' of undefined
A problem occurred configuring project ':react-native-reanimated'.
> [CXX1101] NDK at .../Android/sdk/ndk/26.1.10909125 did not have a source.properties file
Execution failed for task ':react-native-gesture-handler:compileDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction > Compilation error. See log for more details 
error: App.tsx: Cannot find module 'react-native-reanimated/plugin'
Require stack:

위는 모두 gesture-handler와 reanimated 라이브러리 간 버전 불일치 문제로 발생한 에러들이다. 처음에는 ndk 버전이 안맞다고 하여 아예 다시 설치를 해야되는 줄 알았으나, gesture handler와 reanimated를 모두 최신 버전으로 업데이트 후, 무사히 해결되었다. 추가적으로 gesture handler와 reanimated 간의 버전 호환성도 상당히 많은 영향을 끼치기 때문에, 관련 에러가 나타난다면 버전을 잘 알아봐야 한다.

위에서 Swipeable은 세 가지 버전이 있었는데,

import {Swipeable} from 'react-native-gesture-handler';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import Swipeable from 'react-native-gesture-handler/ReanimatedSwipeable';

이렇게 세가지였다. 그래서 처음에는 첫번째 줄의 Swipeable을 사용하여 스와이프 기능을 구현했으나, 이미 더이상 사용되지 않는 버전이라, 지금 지원되는 버전인 세번쨰 줄의 Swipeable을 변경해보기로 도전하였다.

하지만, 여기서 UI 적으로 꼭 해결해야 하는 문제가 발생하였다.

현재 구현하고자 하는 스와이프 기능은 오른쪽으로 스와이프 시 저렇게 별표 모양의 버튼이 나타나야 한다.


하지만, 최신 버전의 Swipeable을 적용해봤더니, 이렇게 스와이프하지 않아도 스와이프해야 나타나야 할 부분이 왼쪽에 일부 보이는 문제가 발생하였다.

추가적으로 찾아보고 해도 최신에 나온 버전이라 아직 issue가 많이 나타나지는 않았는지, 명확한 해결책을 찾을 수 없었다.

    <Swipeable
      friction={2}
      leftThreshold={30}
      overshootLeft={false}
      onSwipeableWillOpen={() => (dragX.value = 1)}
      onSwipeableClose={() => (dragX.value = 0)}
      // renderLeftActions={renderLeftActions}
      renderLeftActions={(progress, dragX) => (
        <LeftActionItem
          dragX={dragX}
          handleOnKeepPress={handleOnKeepPress}
          isKeepPressed={isKeepPressed}
        />
      )}>

해결한 방법은 저 onSwipeableWillOpen과 onSwipeableClose 부분을 보면 되는데, dragX의 value를 수동으로 조절해줌으로써 해결할 수 있었다.

const dragX = useSharedValue(0);

dragX는 이런식으로 미리 초기값을 지정해두고, 사용하면 된다.

여기까지 하니 기능은 얼추 돌아갔지만, 또 해결해야 하는 이슈가 하나 더 있었다.

React Hook "useAnimatedStyle" is called in function "renderLeftActions" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use".eslintreact-hooks/rules-of-hooks

훅을 최상위 컴포넌트에서 호출하지 않아 발생한 문제였는데, renderLeftActions 안에서 useAnimationStyle 훅을 호출한 것이 문제였다.

그래서 이전 코드에서도 보면 renderLeftActions={renderLeftActions} 로 정의를 했다가, 이 문제를 해결하기 위해 LeftActionItem이라는 새로운 컴포넌트로 정의를 함으로써 문제를 해결하였다.

여기서도 중요한 점은, renderLeftActions에 자동으로 원래 progress와 dragX를 함수 인자로 전달하기 때문에, LeftActionItem에도 progress와 dragX를 함수 인자로 전달해야 한다.

정리
라이브러리 중 가장 사용하기 힘들었던 gesture였지만, 그래도 나중에 제스처 기능을 사용할 때는 지금 경험이 도움이 되지 않을까 기대하며..

0개의 댓글