이번 포스트에서는 어제 얘기했었던 디렉토리와 컴포넌트 아키텍쳐를 관한 내용이다.
.
├── App.js
├── README.md
├── app.json
├── babel.config.js
├── package-lock.json
├── package.json
├── node_modules
└── src
├── components
│ ├── addCat
│ │ ├── AddCatBio.js
│ │ ├── AddCatForm.js
│ │ └── AddCatMap.js
│ ├── authInfo
│ │ ├── AuthLoadingScreen.js
│ │ ├── SignIn_Info.js
│ │ └── SignUp_Info.js
│ ├── catInfo
│ │ ├── CatInfoTabs.js
│ │ ├── CatProfile.js
│ │ └── catTabs
│ │ ├── CatAlbum.js
│ │ ├── CatBio.js
│ │ ├── CatComment.js
│ │ ├── CatCommentList.js
│ │ ├── CatFollower.js
│ │ ├── CatFollowerList.js
│ │ ├── CatPhoto.js
│ │ ├── CatPost.js
│ │ ├── CatPostInput.js
│ │ └── CatPostList.js
│ ├── main
│ │ ├── BriefCatInfo.js
│ │ ├── MainMap.js
│ │ └── MainMarker.js
│ └── my
│ ├── MyCat.js
│ ├── MyCatList.js
│ ├── MyProfile.js
│ ├── MyProfile_Elements.js
│ └── PW_Elements.js
├── pages
│ ├── AddCatModal.js
│ ├── AddCatTab.js
│ ├── CatInfo.js
│ ├── ChangePW.js
│ ├── EditMyProfile.js
│ ├── Main.js
│ ├── MyPage.js
│ ├── SelectedPost.js
│ ├── Signin.js
│ └── Signup.js
└── stores
├── CatStore.js
├── UserStore.js
└── index.js
저번 포스트에 추가한 목업 페이지와 컴포넌트구조 링크를 바탕으로 만든 디렉토리이다.
이 중 목업 페이지와 pages
를 바탕으로 react-navigation
구조를 짰다. 먼저 전체적인 코드로는 이런 구조를 띄고 있다.
const MyPageStack = createStackNavigator(
{
MyPage,
EditMyProfile,
ChangePW,
},
{
initialRouteName: 'MyPage',
},
);
MyPageStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
const MainStack = createStackNavigator(
{
Main,
CatInfo,
SelectedPost,
},
{
initialRouteName: 'Main',
},
);
MainStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
const HomeTabs = createBottomTabNavigator(
{
AddCatTab,
MainStack,
MyPageStack,
},
{
initialRouteName: 'MainStack',
defaultNavigationOptions: {
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (navigation.state.key === 'AddCatTab') {
navigation.navigate('AddCatModal');
} else {
defaultHandler();
}
},
},
},
);
const AppStack = createStackNavigator(
{
Home: {
screen: HomeTabs,
navigationOptions: {
headerShown: false,
},
},
AddCatModal,
},
{
initialRouteName: 'Home',
modal: 'modal',
},
);
const AuthStack = createStackNavigator(
{
'Sign In': {
screen: Signin,
navigationOptions: {
headerShown: false,
},
},
'Sign Up': Signup,
},
{
initialRouteName: 'Sign In',
},
);
const RootNavigator = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
Auth: AuthStack,
App: AppStack,
},
{ initialRouteName: 'AuthLoading' },
);
const AppContainer = createAppContainer(RootNavigator);
구조가 아래서부터 위로 추가를 해서 나무 뿌리에서 가지가 뻗어나가는(?) 것과 같은데 아래서부터 설명해보고자 한다. 분리해서 설명하는 코드들도 아래서부터 읽는 것을 추천한다. 가지를 뻗는다고 상상하면 도움이 되기도 한다.
const AppStack = createStackNavigator(
{
Home: {
screen: HomeTabs,
navigationOptions: {
headerShown: false,
},
},
AddCatModal,
},
{
initialRouteName: 'Home',
modal: 'modal',
},
);
const AuthStack = createStackNavigator(
{
'Sign In': {
screen: Signin,
navigationOptions: {
headerShown: false,
},
},
'Sign Up': Signup,
},
{
initialRouteName: 'Sign In',
},
);
const RootNavigator = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
Auth: AuthStack,
App: AppStack,
},
{ initialRouteName: 'AuthLoading' },
);
const AppContainer = createAppContainer(RootNavigator);
먼저 RootNavigator
는 말 그래도 가장 뿌리가 되는 네비게이터이고, 가장 뿌리가 되는 이 RootNavigator
를 createAppContainer()
를 이용하여 컴포넌트화 시켜서 App.js
에서 실행시킨다. 이 RootNavigator
는 stack, tab 과는 다른 switch 네비게이터인데, stack처럼 페이지가 쌓이는 구조도 아닌, screen이 전환된다는 점에서 tab과도 비슷하다고 느껴질 수 있다. 하지만 tab처럼 병렬적 구조가 아닌 한 번에 하나의 screen을 보여주기 때문에 차이가 있다.
RootNavigator
는 세가지 화면이 있는데, AuthLoading
화면에서 토큰이 있는지 확인을 해서 토큰이 존재하지 않는다면 Auth
로 보내 인증 절차(Sign Up
/Sign In
)를 거치게 하고, 토큰이 이미 존재한다면 App
으로 보내 인증 절차를 생략하게 한다.
const HomeTabs = createBottomTabNavigator(
{
AddCatTab,
MainStack,
MyPageStack,
},
{
initialRouteName: 'MainStack',
defaultNavigationOptions: {
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (navigation.state.key === 'AddCatTab') {
navigation.navigate('AddCatModal');
} else {
defaultHandler();
}
},
},
},
);
App
의 구성은 AddCatTab, MainStack, MyPageStack
으로 이루어져 있는 HomeTabs
와 modal창을 띄우는 AddCatModal
이 있다.
defaultNavigationOptions: {
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (navigation.state.key === 'AddCatTab') {
navigation.navigate('AddCatModal');
} else {
defaultHandler();
}
},
},
여기에서 AddCatTab
과 AddCatModal
의 이름이 비슷한데, 사실 AddCatTab
을 터치했을 때 tab처럼 넘어가는게 아닌 새로운 창을 띄우기 위해 위처럼 빈 스크린으로 남겨두고 AddCatModal
을 stack으로 쌓는 방법을 택했다.
const MyPageStack = createStackNavigator(
{
MyPage,
EditMyProfile,
ChangePW,
},
{
initialRouteName: 'MyPage',
},
);
MyPageStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
const MainStack = createStackNavigator(
{
Main,
CatInfo,
SelectedPost,
},
{
initialRouteName: 'Main',
},
);
MainStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
MainStack
은 말 그래도 stack의 구조인데, 지도를 렌더하는 Main
에서 마커를 선택하면 해당 마커에 관한 자세한 정보를 담은 CatInfo
를 쌓게 되고, 그 중 하나의 포스트를 선택하면 SelectedPost
를 또 쌓게 된다.
MainStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
참고로 위의 코드는 네비게이팅을 할 때 옵션을 정해주는 function으로 위 같은 경우는 stack으로 인해 쌓인 상위 구조의 header를 제거해주는 기능을 한다.
마지막으로 설명했었던 SelectedPost
는 사실 4개의 tab으로 이루어진 화면을 구상중인데, 고정적으로 렌더되는 컴포넌트가 있어서 tab navigator보다는 Native Base의 tab을 이용하여 나타내기로 결정하였다.
다음 포스트는 이번 프로젝트에서 가장 큰 시간을 할애했던 react-native-maps 와 관련된 내용을 다룰 예정이다. 힘들게 적용한만큼 정리를 잘 해두어야겠다는 생각이 든다. 짧은 첫번째 프로젝트도 정신없었는데 두번째 프로젝트에서는 시간개념이 희미해졌다. 아직 갈길이 머니 정신차리고 힘을 내야한다. 내일은 오늘보다 더 유익한 하루이길.