jineecode
React navigation (2) 본문
https://jineecode.tistory.com/260
먼저, 내비게이션은 기본적으로 '스택'으로 쌓이기 때문에, 본인이 개발하고자하는 앱의 내비게이션의 흐름을 잘 파악해야 손이 덜 간다.
스택을 제대로 구분하여 나누지 않는다면 부자연스러운 흐름을 직면할 수밖에 없다.
앱의 정책마다 스택의 흐름이 다르고 아래보다 더 좋은 방법이 있을 수 있다.
0. index
import {createStackNavigator} from '@react-navigation/stack';
import {NavigationContainer} from '@react-navigation/native';
import {RootTab} from './RootTab';
const Stack = createStackNavigator();
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="RootTab" component={RootTab} />
</Stack.Navigator>
</NavigationContainer>
가장 근본이 되는 navigation index.tsx.
Root인 NavigationContainer
가 존재한다.
코드가 너무 길어져서 나누었지만, App.tsx에 적어도 무방하다.
1. RootTab
- 여기엔 크게 로그인 화면(AuthStack)과 메인 화면(BottomTab)이 나뉘어져 있다.
- AuthStack에는 로그인, 아이디 비밀번호 찾기, 회원가입 등 auth가 필요없는 페이지들로만 구성되어있다. 즉, 로그인을 하면 볼 일이 없는 screen이다.
- BottomTab은 크게 세 가지의 Navigator로 나뉘어져 있다. 홈, 날씨, 설정. 각각의 Bottom Screen을 대분류로 삼고, 그 아래에 Tree처럼 뻗어나가는 방식을 사용했다.
- 로그인이 성공하면 BottomTab을, 아니라면 AuthStack을 보여주면 된다.
- Redux를 사용하고 있다는 전제하에 다음처럼 개발한다. (isLogInSuccess 는 로그인의 useSelector 이다)
- 이렇게 해주면 내비게이터도 가벼워지고 로그인한 사용자는 로그아웃하지 않는 이상 AuthStack으로 가지 못해서 버그를 방지할 수 있다.
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
{isLogInSuccess ? (
<Stack.Screen name="BottomTab" component={BottomTab} />
) : (
<Stack.Screen name="AuthStack" component={AuthStack} />
)}
</Stack.Navigator>
2. AuthStack
- 앞서 말한 것처럼 로그인 화면의 구조는 Login, SignUp, FindId 등의 Screen이 모여있는 내비게이터다.
- 이 앱은 One thing per page UX를 갖추고 있어서 Screen이 몹시 많다. 컴포넌트로 쪼갤 수 있는 건 최대한 쪼개는 게 좋다.
- Stack.Screen 자체를 컴포넌트로 만들어 썼는데, 이렇게 할 경우 기능 추가를 하거나 개별적으로 커스텀을 할 때 혼란이 올 수 있다. 취향껏 개발하자!
import {useNavigation} from '@react-navigation/native';
import IconCloseImg from '~/assets/images/icon_navigation_close.svg';
import {GoToButtonWrapper} from '~/components/styles/Mixin';
import NavigationModal from '~/components/atoms/Modal/NavigationModal';
export const Features = ({
name,
screen,
customOptions,
isDepth,
isRight,
isModal,
listeners,
initialParams,
}: Iprops) => {
return (
<Stack.Screen
name={name}
component={screen}
listeners={listeners}
initialParams={initialParams}
options={() => ({
headerTintColor: '#000000',
headerTitleStyle: {
fontWeight: 'bold',
fontSize: Theme.fontSize(18),
},
headerLeft: () =>
isDepth ? (
<GoToButtonWrapper onPress={() => GoToBack} activeOpacity={0.5}>
<GoToBack isModal={isModal} />
</GoToButtonWrapper>
) : null,
headerRight: () =>
isRight && (
<GoToButtonWrapper activeOpacity={0.5}>
<GoToButton screenName="LogIn" />
</GoToButtonWrapper>
),
...customOptions,
})}
/>
);
};
const SignUpModal = ({navigation}) => {
return (
<NavigationModal
isTwoBtn
isSubTitle
label="확인"
navigation={navigation}
modalTextLabel={'회원가입을 중단하고 나가시겠어요?'}
clearDispatch={userClear()}
navigationScreen={'LogIn'}
/>
);
};
const SignUpHeaderRight = () => {
const navigation = useNavigation();
return {
title: '회원가입',
headerBackTitleVisible: false,
headerTitleAlign: 'left',
headerRight: () => (
<GoToButtonWrapper activeOpacity={0.5}>
<IconCloseImg
onPress={(e) => {
e.preventDefault();
navigation.navigate('SignUpModal');
}}
/>
</GoToButtonWrapper>
),
presentation: 'transparentModal',
};
};
export const AuthStack = () => {
return (
<Stack.Navigator>
{Features({
name: 'LogIn',
screen: LogIn,
customOptions: {headerShown: false},
})}
{Features({
name: 'SignUpModal',
screen: SignUpModal,
customOptions: SignUpHeaderRight(),
isDepth: true,
isRight: true,
})}
{Features({
name: 'SignUpTerms',
screen: SignUpTerms,
customOptions: SignUpHeaderRight(),
isDepth: true,
isRight: true,
})}
...
</Stack.Navigator>
);
};
3. BottomTab
- 바텀탭은 3가지 Tab으로 나뉘어져 있다.
- 각각의 커다란 탭 안에서 Screen으로 다시 쪼개주면 된다.
- ex) WeatherTab
- Weather
- Past
- Today
- Forcast
- WeatherTutorial
- Weather
export const BottomTab = () => {
return (
<Tab.Navigator
initialRouteName="HomeTab"
screenOptions={{
headerShown: false,
tabBarLabelStyle: {
fontSize: Theme.fontSize(12),
},
tabBarStyle: {
height: 56,
paddingTop: Theme.height(5),
paddingBottom: Theme.height(5),
},
tabBarHideOnKeyboard: true,
tabBarActiveTintColor: '#005500',
}}>
<Tab.Screen
name="HomeTab"
component={HomeTab}
options={{
tabBarLabel: '홈',
tabBarIcon: ({focused}) => (focused ? <IconHomeAct /> : <IconHome />),
}}
/>
<Tab.Screen
name="WeatherTab"
component={WeatherTab}
listeners={({navigation}) => ({
tabPress: (e) => {
if (!hasFarmlands) {
e.preventDefault();
navigation.navigate(`NoFarmModal${navigation.getState().index}`);
}
},
})}
options={{
tabBarLabel: '날씨',
tabBarIcon: ({focused}) =>
focused ? <IconWeatherAct /> : <IconWeather />,
}}
/>
<Tab.Screen
name="SettingTab"
component={SettingTab}
options={{
tabBarLabel: '설정',
tabBarIcon: ({focused}) =>
focused ? <IconSettingAct /> : <IconSetting />,
}}
/>
</Tab.Navigator>
);
};
'React native' 카테고리의 다른 글
react-native toast 사용하기 [react-native-toast-message] (0) | 2022.05.24 |
---|---|
React navigation (3) (0) | 2022.05.23 |
React navigation (1) (0) | 2022.05.23 |
RN 반응형 디자인 적용법 (0) | 2022.02.17 |
각종 에러들 타파하기 (0) | 2022.02.09 |
Comments