오티스의개발일기

[REACT NATIVE] 인스타그램 클론 코딩 (14) gorhom/bottom-sheet 를 활용한 바텀 시트 만들기 본문

개발/react-native

[REACT NATIVE] 인스타그램 클론 코딩 (14) gorhom/bottom-sheet 를 활용한 바텀 시트 만들기

안되면 될때까지.. 2023. 1. 1. 23:26
728x90


< 이전글

2023.01.01 - [개발/react-native] - [REACT NATIVE] 인스타그램 클론 코딩 (13) 마이페이지 ui 만들기

 

[REACT NATIVE] 인스타그램 클론 코딩 (13) 마이페이지 ui 만들기

< 이전글 2023.01.01 - [개발/react-native] - [REACT NATIVE] 인스타그램 클론 코딩 (12) AsyncStorage 를 사용하여 jwt 토큰 저장하기 [REACT NATIVE] 인스타그램 클론 코딩 (12) AsyncStorage 를 사용하여 jwt 토큰 저장하기

otis.tistory.com



다음글 >

 

2023.01.02 - [개발/react-native] - [REACT NATIVE] 인스타그램 클론 코딩 (15) 로그아웃 구현하기

 

[REACT NATIVE] 인스타그램 클론 코딩 (15) 로그아웃 구현하기

< 이전글 2023.01.01 - [개발/react-native] - [REACT NATIVE] 인스타그램 클론 코딩 (14) gorhom/bottom-sheet 를 활용한 바텀 시트 만들기 [REACT NATIVE] 인스타그램 클론 코딩 (14) gorhom/bottom-sheet 를 활용한 바텀 시트

otis.tistory.com


 

 

 

오늘은 gorhom/bottom-sheet 를 활용하여 바텀 시트를 만들어볼것이다

원래는 로그아웃까지 구현하는 포스팅을 올리려했는데

너무 길어질것같아 오늘은 ui만 제작 해보려고한다.

 

이거 지금 두번쓰는 중이다....

티스토리 이놈.... 임시저장했는데 없어져버렸다......

화가나지만 마음을 가다듬고 시작해보겠다..

 

 


# 오늘 작업할 파일목록

  • App.js
  • babel.config.js
  • BottomNavigation.js
  • myPageBottomSheet.js
  • Header.js(/src/screens/myPage/Header.js)

# 0. 폴더 구조



 

일단 라이브러리를 다운로드 받아보도록 하겠다.

터미널을 열고 명령어를 작성해보자.


  
yarn add @gorhom/bottom-sheet@^4
yarn add react-native-reanimated react-native-gesture-handler

 

 

라이브러리를 다받았으면 설정해야하는 파일이 몇개가있다.

 

첫번째는 babel.config.js 파일이다.


  
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin'], // <---- 추가한것
};

주석으로 적어놨으니 확인하기바란다.

reanimated 라이브러리를 사용하려면 플러그인에 등록해야하는 하지않으면 오류가 뜰것이다.

 

두번째는 react-native-gesture-hanlder 모듈이다.

이게 이번에 바뀐거같다.

 

이 제스처 모듈을 사용하려면 루트 파일 상단에 감싸줘야한다.

이것때문에 한 삼십분은 삽질한거같다 ㅎㅎ


  
import {Provider} from "react-redux";
import store from "./store";
import { StyleSheet, Text, View } from 'react-native'
import AuthNavigaitor from './src/navigations/AuthNavigaiton'
import {GestureHandlerRootView} from 'react-native-gesture-handler'
import { SafeAreaView } from "react-native";export default function App() {
return (
<Provider store={store}>
<GestureHandlerRootView style={{ flex: 1 }}>
<AuthNavigaitor/>
</GestureHandlerRootView>
</Provider>
);
}

 

<GestureHandlerRootView><GestureHandlerRootView>

이 태그를 꼭 감싸주도록 하자.

 

 

시작하기전 참고사항이있다.

본인은 바텀시트가 바텀네비게이션을 가려야하기때문에

BottomNavigation.js 에 작업을 하였다.

 

이제 본격적으로 시작해보도록 하겠다.

 

 

# 1. BottomNavigation.js

 


  
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
import React, { useCallback, useMemo, useRef } from 'react';
import {
BottomSheetModal,
BottomSheetModalProvider,
} from '@gorhom/bottom-sheet';
import {ROUTES} from '../constants/routes';
import HomeScreen from '../screens/HomeScreen';
import CartScreen from '../screens/CartScreen';
import MyPageScreen from '../screens/MyPageScreen';
import PlayScreen from '../screens/PlayScreen';
import SearchScreen from '../screens/SearchScreen';
import styled from 'styled-components/native'
import Ionicons from "react-native-vector-icons/Ionicons";
import {BOTTOM_ICONS} from '../constants/icons';
import { useSelector, useDispatch } from 'react-redux';
import bottomSheetSlicer from '../slicers/bottomSheetSlicer'
import MyPageBottomSheet from '../screens/bottomSheet/MyPageBottomSheet'
const Tab = createBottomTabNavigator();
const BottomNavigation = (props) => {
const { navigation } = props; // 네비게이션
const dispatch = useDispatch();
const theme = useSelector((state) => state.themeSlicer.theme);
// ref
const bottomSheetModalRef = useRef(null);
// variables
const snapPoints = useMemo(() => ['25%', '50%'], []);
// callbacks
const handlePresentModalPress = useCallback(() => {
bottomSheetModalRef.current?.present();
}, []);
const handleSheetChanges = useCallback((index) => {
console.log('handleSheetChanges', index);
if (index === -1) {
dispatch(bottomSheetSlicer.actions.updateSlicer({name : 'myPage', active: false}))
}
}, []);
const bottomSheet = useSelector((state) => state.bottomSheetSlicer);
if (bottomSheet.active) {
switch(bottomSheet.name) {
case 'myPage' :
handlePresentModalPress();
break;
}
}
return (
<>
<Tab.Navigator initialRouteName={ROUTES.HOME}
screenOptions={({route}) => ({
headerShown: false,
tabBarShowLabel: false,
tabBarStyle: {
borderTopWidth: 1,
borderTopColor: '#61616236',
height: 90,
padding: 10,
backgroundColor: theme.backgroundColor,
},
tabBarIcon: ({color, size, focused}) => {
let iconName;
if (route.name === ROUTES.HOME) {
iconName = focused ? BOTTOM_ICONS.HOME.activeIcon : BOTTOM_ICONS.HOME.inActiveIcon
} else if (route.name === ROUTES.SEARCH) {
iconName = focused ? BOTTOM_ICONS.SEARCH.activeIcon : BOTTOM_ICONS.SEARCH.inActiveIcon
} else if (route.name === ROUTES.PLAY) {
iconName = focused ? BOTTOM_ICONS.PLAY.activeIcon : BOTTOM_ICONS.PLAY.inActiveIcon
} else if (route.name === ROUTES.CART) {
iconName = focused ? BOTTOM_ICONS.CART.activeIcon : BOTTOM_ICONS.CART.inActiveIcon
} else if (route.name === ROUTES.MYPAGE) {
return <Avatar source={{uri: 'https://i.ibb.co/ZhB1QPv/image.jpg'}}/>
}
return <Ionicons name={iconName} size={28} color={theme.TextColor}/>
}
})}>
<Tab.Screen name={ROUTES.HOME} component={HomeScreen} ></Tab.Screen>
<Tab.Screen name={ROUTES.SEARCH} component={SearchScreen}></Tab.Screen>
<Tab.Screen name={ROUTES.PLAY} component={PlayScreen}></Tab.Screen>
<Tab.Screen name={ROUTES.CART} component={CartScreen}></Tab.Screen>
<Tab.Screen name={ROUTES.MYPAGE} component={MyPageScreen}></Tab.Screen>
</Tab.Navigator>
<BottomSheetModalProvider>
<View>
<BottomSheetModal
ref={bottomSheetModalRef}
index={1}
snapPoints={snapPoints}
onChange={handleSheetChanges}
>
<View>
<MyPageBottomSheet navigation={navigation}/>
</View>
</BottomSheetModal>
</View>
</BottomSheetModalProvider>
</>
)
}
const Avatar = styled.Image`
width: 32px;
height: 32px;
border-radius: 50px;
border-width: 2px;
border-color: white;
`;
const View = styled.View``
const Text = styled.Text``
const Button = styled.Button``
export default BottomNavigation

 

 

기본적으로 어떤 바텀 네비게이션이 추가될지몰라

BottomNavigation 에 중점을 두고 myPageBottomSheet.js 라는 파일을 따로 빼두었다.

 

# 2.myPageBottomSheet.js


  
import styled from "styled-components/native";
import React from 'react'
import {Divider} from 'react-native-elements'
import Ionicons from "react-native-vector-icons/Ionicons";
import {ICONS} from '../../constants/icons'
import {Alert} from 'react-native'
import { useDispatch, useSelector } from "react-redux"; // userDispatch = 데이터 변경시 사용 // useSelector = 데이터 가져올때 사용
import {logOutRequest} from '../../actions/userAction'
import * as $Util from '../../constants/utils'
const myPageBottomSheet = ({navigation}) => {
const dispatch = useDispatch();
const openLogOutAlert = () => {
return (
Alert.alert(
'로그아웃 하시겠습니까?',
'로그아웃',
[
{
text: '로그아웃',
onPress: () => {dispatch(logOutRequest(navigation))}
},
{
text: '취소',
style: "cancel"
},
],
{ cancelable: false }
)
)
}
return (
<Container>
<TouchableOpacity onPress={openLogOutAlert}>
<Box>
<TextBox>
<Ionicons name="log-out-outline" size={28} color="black" />
<Text>로그아웃</Text>
</TextBox>
<Divider width={1}/>
</Box>
</TouchableOpacity>
</Container>
)
}
export default myPageBottomSheet
const Container = styled.View`
padding: 10px 15px;
`
const Box = styled.View``
const TextBox = styled.View`
flex-direction: row;
align-items: center;
margin-bottom: 10px;
`
const Text = styled.Text`
margin-left: 10px;
`
const TouchableOpacity = styled.TouchableOpacity`
`;

 

 

 

 

자이제 동적하는지 확인해보겠다.

 

 

 

정상적으로 동작하는걸 확인할수있다.

 

이것으로 포스팅을 마치도록 하겠다.

 

다음 포스팅에는 진짜로 로그아웃을 구현할것이니 참고하기 바란다.

 

 

 

 

# 깃허브 주소


https://github.com/1domybest/react-native-ig-clone.git

 

GitHub - 1domybest/react-native-ig-clone

Contribute to 1domybest/react-native-ig-clone development by creating an account on GitHub.

github.com

 


다음글 >

2023.01.02 - [개발/react-native] - [REACT NATIVE] 인스타그램 클론 코딩 (15) 로그아웃 구현하기

 

[REACT NATIVE] 인스타그램 클론 코딩 (15) 로그아웃 구현하기

< 이전글 2023.01.01 - [개발/react-native] - [REACT NATIVE] 인스타그램 클론 코딩 (14) gorhom/bottom-sheet 를 활용한 바텀 시트 만들기 [REACT NATIVE] 인스타그램 클론 코딩 (14) gorhom/bottom-sheet 를 활용한 바텀 시트

otis.tistory.com


 

728x90
Comments