리액트 네이티브에서 bottom sheet을 사용하는 방법을 작성하고자 한다.
Bottom Sheet란?
Bottom Sheet란 사진처럼 아래에서 올라오는 컴포넌트를 의미한다. UX를 고려하여 thumb zone에 맞게 적절한 높이를 지니고 있으며 다양한 앱 및 웹 서비스에 쉽게 볼 수 있는 컴포넌트이다.
이를 별도 라이브러리 없이 구현하고자 하였으나, 여러 문제가 발생했고 npm 통계 상 라이브러리가 매우 자주 사용되고 있음을 확인하여 성능에 문제가 없겠다 싶어 라이브러리를 적용하기로 했다.
https://www.npmjs.com/package/@gorhom/bottom-sheet
@gorhom/bottom-sheet
A performant interactive bottom sheet with fully configurable options 🚀. Latest version: 5.0.6, last published: a month ago. Start using @gorhom/bottom-sheet in your project by running `npm i @gorhom/bottom-sheet`. There are 187 other projects in the np
www.npmjs.com
https://gorhom.dev/react-native-bottom-sheet/
Bottom Sheet | React Native Bottom Sheet
A performant interactive bottom sheet with fully configurable options 🚀
gorhom.dev
더 자세한 사항은 위의 공식 문서를 따라가면 된다.
여러 블로그 글이 있었지만 이전 버전인 것인지, 최신 버전의 적용 방법과 조금 다른 부분이 있어 항상 공식 문서를 따라하는 걸 추천한다.
특히 이 부분이 빠지면. 사용할 수 없으니 꼭 읽고 적용하길 바란다.
사용 방법
import React, { useCallback, useMemo, useRef } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';
const App = () => {
// ref
const bottomSheetRef = useRef<BottomSheet>(null);
// callbacks
const handleSheetChanges = useCallback((index: number) => {
console.log('handleSheetChanges', index);
}, []);
// renders
return (
<GestureHandlerRootView style={styles.container}>
<BottomSheet
ref={bottomSheetRef}
onChange={handleSheetChanges}
>
<BottomSheetView style={styles.contentContainer}>
<Text>Awesome 🎉</Text>
</BottomSheetView>
</BottomSheet>
</GestureHandlerRootView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'grey',
},
contentContainer: {
flex: 1,
padding: 36,
alignItems: 'center',
},
});
export default App;
먼저 GestureHandlerRootView를 감싼 후 flex:1로 화면을 꽉 채워주어야 한다.
이후 BottomSheet를 호출하여 사용하면 된다.
이 중 내가 직접 사용한 props를 보여주고자 한다.
const [bottomSheetState, setBottomSheetState] = useState(-1);
const renderBackdrop = useCallback(
(props: any) => (
<BottomSheetBackdrop
{...props}
disappearsOnIndex={-1} // index가 -1일 때 배경 사라짐
appearsOnIndex={0} // index 0 이상일 때 배경 등장
opacity={0.5} // 배경 어두움 정도 설정
/>
),
[],
);
const handleSheetChanges = useCallback((index: number) => {
setBottomSheetState(index);
}, []);
return (
<BottomSheet
ref={bottomSheetRef}
onChange={handleSheetChanges}
enablePanDownToClose={true}
enableDynamicSizing={false} // 이게 있어야 0번 인덱스가 내가 설정한 40%로 설정됨
index={bottomSheetState}
snapPoints={['40%', '80%']}
backdropComponent={renderBackdrop} // Backdrop 추가
>
{children}
</BottomSheet>
);
index : Bottom Sheet의 열린 상태를 index로 제어한다. -1이면 닫힌 상태, 0 이상이면 열린 상태이다. 초기값을 -1로 두면 닫힌 상태에서 시작하고 0으로 두면 열린 상태에서 시작한다.
snapPoints: Bottom Sheet의 위치를 지정한다. 이는 index와 함께 쓰이는데 snapPoinst에 지정된 배열에 따라 index가 0번이면 ['40%' , '80%'] 에서 40% 높이만큼 올라오고 index가 1번이면 80%로 올라온다. 픽셀 값으로 숫자만 넣어도 되고 퍼센트로 지정할 거면 string이어야 한다.
enableDynamicSizing: snapPoints, index를 제대로 지정해도 뭔가 이상한 게 있을 것이다. 바로 내가 지정하지 않은 위치에 Bottom Sheet가 위치하는 경우가 생긴다.
이는 Bottom Sheet 자체에서 미리 지정한 값이 snapPoints에 추가되어 사용되기 때문이다. 이는 픽셀 100의 값이 0번 인덱스에 추가되는데 ['40%' , '80%']으로 지정했으면 [100, '40%' , '80%']으로 사용되는 것이다. 그래서 index가 0번이면 내가 직접 지정한 40%가 아닌 100의 위치에 있는 것이다. 이를 사용하지 않기 위해서는 enableDynamicSizing를 꼭 false값으로 지정해야한다.
enablePanDownToClose : BottomSheet를 아래로 내리면 Bottom Sheet가 닫히게 된다.
대충 이정도로만 정리하면 충분히 원하는 bottom sheet를 구현할 수 있다.
'React & React Native' 카테고리의 다른 글
React Native navigation 파헤치기 (0) | 2024.11.17 |
---|---|
Framer Motion 속성 정리 (0) | 2024.07.02 |
Bottom Sheet (React로 구현하기) (0) | 2024.05.06 |
Kakao Map Api 사용하기 (with React) (0) | 2024.03.14 |
React Modal (0) | 2024.02.08 |