React Navigation setup
리액트 네이티브 공식 문서를 살펴보면, Pagination 또는 Navigation을 원한다면 React Navigation 모듈을 사용하길 권장하고 있다.
다음 과정을 거쳐 나의 프로젝트에 React Navigation을 다운로드 해주었다.
- 먼저 프로젝트에 npm install 해주었다.
> npm install @react-navigation/native
- 그다음 나 같은 경우는 Expo CLI를 사용하는 것이 아닌, ReactNative CLI를 사용하고 있기 때문에, npm install로 새로운 dependencies를 설치해 주었다.
> npm install react-native-screens react-native-safe-area-context
리액트 네이티브 0.60 버전 이후 버전부터는 linking이 자동적으로 되기 때문에 react native link를 사용하지 않아도 될뿐더러 작업할 것이 현저히 적어졌다. 그래도 MAC에서 ios 개발을 하려고 한다면 Cocoapod가 필수적으로 필요하다는 것을 공식 문서에서도 강조하고 있다.
cd ios
pod install
cd ..
나 같은 경우는 M1 Pro를 탑재한 맥북 프로를 사용하고 있다. M1 Architechture에선 제대로 Cocoapods가 작동되지 않는다. 따라서, Roseta 2를 활용하거나 ffi 모듈을 사용하여 다음과 같은 방식으로 pod를 다운로드해주어야 한다.
sudo arch -x86_64 gem install ffi
arch -x86_64 pod install
그리고 안드로이드 개발을 위하여 다음과 같은 설정 또한 진행해주어야 한다.
프로젝트 폴더 안의 android/app/src/main/java/<your package name>/MainActivity.java 에서 다음 코드를 추가하여 주면 된다.
import android.os.Bundle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}
그리고 Stack Navigator에 대한 정리부터 할 예정이라 stack navigator library 또한 다운로드하여야 할 거 같다.
npm install @react-navigation/native-stack
모두 완료했다면 React Native Navigation을 사용할 준비가 되었다는 뜻이다.
React Stack Navigation
import * as React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from './src/home';
import UserScreen from './src/user';
const Stack = createNativeStackNavigator();
function App() {
return(
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen}/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default App;
- 먼저 NavigationContainer와 createNativeStackNavigator를 import 해온다.
- createNativeStackNavigator는 screen이랑 navigator라는 두 개의 property를 리턴하는 함수이다. 화면이 렌더링 되는 부분에서 Stack.Navigator라는 태그를 작성할 것이다.
- <Stack.Navigator>와 <Stack.Screen>은 createNativeStackNavigator로 구동된다.
- 중요한 점으론 React 17 버전부터 중요시되어온 함수형 컴포넌트로 작성하여야 제대로 구동이 된다는 점이다.
//home.js
import * as React from 'react';
import { View, Text } from 'react-native';
function HomeScreen() {
return(
<View>
<Text>HomeScreen</Text>
</View>
)
}
export default HomeScreen;
- 다음 home.js를 import 하여 받아온 화면이다.
- Stack.Screen 태그의 name은 Application Header의 이름이 되고, 그 안에 home.js의 내용이 들어가게 된다. 또한 Navigation Container를 사용하게 되면 SafeArea도 자동으로 설정되게 된다.
Stack Navigation의 화면 전환
import * as React from 'react';
import { View, Text, Button } from 'react-native';
function HomeScreen({ navigation }) {
return(
<View>
<Text>HomeScreen</Text>
<Button
title="To UserScreen"
onPress={()=>{
navigation.navigate('User');
}}
/>
</View>
)
}
export default HomeScreen;
- Navigation의 navigate라는 함수를 끌어오면 된다.
- 앞서 선언했던 Stack은 createNativeStackNavigaton함수인데, 이 함수는 Screen이라는 property를 리턴할 때 ScreenComponent를 명시해주는데 내비게이션 프롭스를 각각의 ScreenComponent에다가 넘겨준다. 따라서 각각의 Screen Component에선 navigation.navigate를 사용할 수 있게 된다.
- navigate 함수의 인자로는 Screen 이름을 작성하여 주면 된다.
//App.js
<Stack.Screen name="Home" component={HomeScreen}/>
<Stack.Screen name="User" component={UserScreen}/>
//home.js
<Button
title="To UserScreen"
onPress={()=>{
navigation.navigate('User');
}}
/>
Stack Navigation Params (데이터 전달)
먼저 Route 설정을 할 수 있는 문법을 알아보고 넘어가자. 현재의 최상단 Route는 제일 상단의 Stack.Screen인 Home이다. User 먼저 나오게 즉, initialRoute로 만들어주려면 다음과 같이 initialRouteName을 사용하여 보자.
<Stack.Navigator initialRouteName='User'>
<Stack.Screen name="Home" component={HomeScreen}/>
<Stack.Screen name="User" component={UserScreen}/>
</Stack.Navigator>
- React Native에선 다른 Route로 데이터를 넘기는 것을 Passng prameters라고 부른다.
function HomeScreen({ navigation }) {
return(
<View>
<Text>HomeScreen</Text>
<Button
title="To UserScreen"
onPress={()=>{
navigation.navigate('User',
{
userIndex: 100,
userName: 'Gildong',
userLastName: 'Hong',
}
);
}}
/>
</View>
)
}
- Home.js에다가 userIndex, userName, userLastName이라는 인자들을 객체로 만들어 놓았다.
- 그리고 받는 User.js는 다음과 같이 작성하면 params를 passing 할 수 있을 것이다.
import * as React from 'react'
import { View, Text, Button } from 'react-native';
function UserScreen({navigation, route}){
const {params} = route;
const userIndex = params ? params.userIndex : null;
const userName = params ? params.userName : null;
const userLastName = params ? params.userLastName : null;
console.log(params)
return(
<View>
<Text>UserScreen</Text>
<Button
title="To HomeScreen"
onPress={()=>{
navigation.navigate('Home');
}}
/>
<Text>User index: {JSON.stringify(userIndex)}</Text>
<Text>User Name: {JSON.stringify(userName)}</Text>
<Text>User LastName: {JSON.stringify(userLastName)}</Text>
</View>
)
}
export default UserScreen;
- 먼저 props로 route를 받아 온 뒤 params라는 객체로 데이터들을 받아 와 준다.
- 그리고 각각의 값들이 있으면 그 값을 const로 새롭게 변수로 생성해 주고 아니면 null 값을 대입하여 주는 코드를 작성했다.
- 그리고 현재 params 객체로 있는 값을 JSON.stringfy라는 함수를 통해 값을 문자열로 치환해주고 출력할 수 있게 만들어 주었다.
Passing이 아닌 initialize 할 때 만들기
<Stack.Screen
name="User"
component={UserScreen}
initialParams={{
userIndex: 50,
userName: 'Gildong',
userLastName: 'Ung',
}}
/>
- initialParams를 통하여 만들어 준다.
Stack Navigator header bar 설정하기
Stack.Screen은 자동으로 header bar를 만들어주고 기본 값은 name의 값이 자동으로 들어가게 된다.
<Stack.Screen
name="Home"
component={HomeScreen}
options={{title: 'Home Screen'}}
/>
방금 알아본 것은 initialtitle이었고 버튼을 눌렀을 때 해당 Header의 Title을 바꾸는 좋은 방법이 있다.
//home.js
<Button
title="changeHeader"
onPress={() => navigation.setOptions({ title: 'Updated!' })}
/>
- props로 받아온 navigation의 setOptions라는 함수를 호출하여 객체 내의 title을 바꿀 수 있다.
- title 뿐만 아니라 setOptions라는 이름을 보면 headerbar의 색상, 모양 또한 변경이 가능하다.
- https://reactnavigation.org/docs/headers
<Button
title="changeHeader"
onPress={() => navigation.setOptions({
title: 'Updated!',
headerStyle: {
backgroundColor: 'pink'
}
})}
/>
- 예시로 backgroundColor를 pink 색상으로 변경해 보았다. 이외에도 다양한 설정들이 가능하니 공식 문서를 참조하면 된다.
또한 각 Screen.js에서 각 header의 색상 또는 스타일을 지정할 수 있다.
import * as React from 'react';
import { View, Text, Button } from 'react-native';
function HomeScreen({ navigation }) {
React.useLayoutEffect(() => {
navigation.setOptions({
title: '여긴 홈 스크린입니다.',
headerStyle:{
backgroundColor: 'blue',
},
headerTintColor: 'yellow'
})
})
this.headerStyle();
return(
<View>
<Text>HomeScreen</Text>
</View>
)
}
export default HomeScreen;
- useLayoutEffect라는LifeCycle hook을 이용하여 setOptions를 control 해줘야 한다.
- Hook에 대한 설명은 다음에 하도록 하겠다.
- 만약 function component가 아닌 class component 였다면 함수 하나를 만들고 그 함수를 render 함수에 호출해줬다면 괜찮았겠지만, 다음 코드는 function component로 제작되어야 하기 때문에 useLayoutEffect를 사용하여 navigation.setOptions를 만들어 줬다.
모든 화면에 같은 header Style 적용하기
//App.js
<NavigationContainer>
<Stack.Navigator
initialRouteName='Home'
screenOptions={
{
headerStyle:{
backgroundColor: 'brown',
},
headerTintColor: 'yellow'
}
}
>
- 다음과 같이 Stack.Screen 태그를 감싸고 있는 Stack.Navigator 태그 안에 screenOptions property에 스타일 값들을 할당해 주면 따로 설정하지 않은 모든 header style에 자동으로 적용된다.
HeaderBar 커스터마이징 하기
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'Home Screen',
headerTitle: ()=> <Image style={{width: 40, height: 40}} source ={require('./src/assets/pics/home_icon.png')}/>
}}
/>
- headerTitle에 arrowFunction 형태로 함수형 컴포넌트를 넣어주면 된다. 나 같은 경우 home_icon이라는 assets를 가져와 제작해 보았다.
Header Bar에 버튼 추가하기
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'Home Screen',
headerTitle: () => (
<Image
style={{width: 40, height: 40}}
source={require('./src/assets/pics/home_icon.png')}
/>
),
headerRight: ()=>(
<Button
title ="Info"
onPress={()=>alert("Button Pressed")}/>
)
}}
/>
- 다음과 같이 headerRight property에 function Component로 작성하면 된다.
Drawer Navigator
Drawer Navigator란? 화면 좌측이나 우측에서 튀어나오는 새로운 화면을 뜻한다.
- 다음 영상에서 나오듯, 다음과 같이 왼쪽 또는 오른쪽에서 튀어 나오는 듯 한 애니메이션을 가지고 나오는 UI를 Drawer라고 한다.
StackNavigator를 사용하는 것과 마찬가지로 npm을 통하여 따로 설치를 해주어야 제대로 된 사용이 가능하다.
npm install @react-navigation/drawer
npm install react-native-gesture-handler react-native-reanimated
//app.js
import 'react-native-gesture-handler';
- React Navigation v6.x가 되면서 gesture-handler는 사용하지 않는 것으로 알았으나 특정 부분은 아직 5.x 버전과 같다는 것을 알았다.
- 다음과 같이 import 해준 후 전역으로 Stack과 똑같이 Drawer라는 변수를 만들어 주자.
const Drawer = createDrawerNavigator();
//app.js
import * as React from 'react';
import {StyleSheet, View, Text, Image, Button} from 'react-native';
import 'react-native-gesture-handler';//추가
import {NavigationContainer} from '@react-navigation/native';
import { createDrawerNavigator } from '@react-navigation/drawer'; //추가
import DrawerHomeScreen from './src/home_drawer';
import DrawerUserScreen from './src/user_drawer';
const Drawer = createDrawerNavigator();
function App() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name = "Home" component={DrawerHomeScreen}/>
<Drawer.Screen name = "User" component={DrawerUserScreen}/>
</Drawer.Navigator>
</NavigationContainer>
);
}
export default App;
//user_drawer.js
import * as React from 'react'
import { View, Text, Button } from 'react-native';
function DrawerUserScreen({navigation}){
return(
<View>
<Text>UserScreen</Text>
<Button
title="To HomeScreen"
onPress={()=>{
navigation.navigate('Home');
}}
/>
</View>
)
}
export default DrawerUserScreen;
같은 구조로 home_drawer.js도 작성해 주었다.
- 다음과 같이 Stack과 다른 HeaderBar가 나오게 된다.
- Drawer.Navigator 태그의 property로는 drawerType, drawerPosition, drawerStyle 등이 있다.
- 각 property를 통한 커스텀 또한 가능하다.
DrawerItem 추가하기
import * as React from 'react';
import {StyleSheet, View, Text, Image, Button, Linking} from 'react-native';
import 'react-native-gesture-handler';
import {NavigationContainer} from '@react-navigation/native';
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem } from '@react-navigation/drawer';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import DrawerHomeScreen from './src/home_drawer';
import DrawerUserScreen from './src/user_drawer';
const Stack = createNativeStackNavigator();
const Drawer = createDrawerNavigator();
function App() {
CustomDrawerContent = (props) => {
return(
<DrawerContentScrollView {...props}>
<DrawerItemList {...props}/>
<DrawerItem
label ="Help"
onPress={()=>Linking.openURL('http://www.google.com')}
/>
<DrawerItem
label ="Info"
onPress={()=>alert('info window')}
/>
</DrawerContentScrollView>
)
}
return (
<NavigationContainer>
<Drawer.Navigator
drawerContent={props=><this.CustomDrawerContent {...props}/>}>
<Drawer.Screen name = "Home" component={DrawerHomeScreen}/>
<Drawer.Screen name = "User" component={DrawerUserScreen}/>
</Drawer.Navigator>
</NavigationContainer>
);
}
export default App;
- 다음과 같이 요소 추가도 가능하다. DrawerContentScrolView에 DrawerItem들을 가져오면 된다.
Tab Navigator
React Navigation 공식 문서에선 Bottom Tabs Navigator라고 불린다. 하단 탭의 버튼들로 Navigation 하는 UI요소이다.
npm install @react-navigation/bottom-tabs
- 앞서 사용했던 Stack과 Drawer와 같게 npm을 통하여 설치해 주었다.
import * as React from 'react';
import {StyleSheet, View, Text, Image, Button, Linking} from 'react-native';
import 'react-native-gesture-handler';
import {NavigationContainer} from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import TabHomeScreen from './src/home_tab';
import TabUserScreen from './src/user_tab';
const Tab = createBottomTabNavigator();
function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={TabHomeScreen}/>
<Tab.Screen name="User" component={TabUserScreen}/>
</Tab.Navigator>
</NavigationContainer>
);
}
export default App;
//home_tab.js
import * as React from 'react';
import { View, Text, Button } from 'react-native';
function TabHomeScreen({ navigation }) {
React.useLayoutEffect(() => {
navigation.setOptions({
title: '여긴 홈 스크린입니다.',
})
})
return(
<View>
<Text>HomeScreen</Text>
<Button
title="To UserScreen"
onPress={()=>{
navigation.navigate('User');
}}
/>
</View>
)
}
export default TabHomeScreen;
마찬가지로 user_tab.js와 home_tab.js의 구조를 같게 작성했다.
- 다음과 같이 Icon과 이름이 달린 하단 Bar가 생겼고 다음 버튼들을 클릭하면 Pagination이 가능하다.
function App() {
return (
<NavigationContainer>
<Tab.Navigator
initialRouteName='User'
screenOptions={{
tabBarShowLabel: false,
tabBarActiveTintColor: 'red'
}}
>
<Tab.Screen name="Home" component={TabHomeScreen} />
<Tab.Screen name="User" component={TabUserScreen}/>
</Tab.Navigator>
</NavigationContainer>
);
}
- 다음과 같이 특별한 custom도 screenOption를 통해 가능하다.
여기까지 자주 사용되는 Navigator들을 살펴보았다. 화면 구조 설계(Nesting Navigator)에 대해서도 한번 알아봐야겠다.
'프론트엔드 개발 > React Native' 카테고리의 다른 글
[React Native] Components(1) (0) | 2022.07.07 |
---|---|
[React Native] Expo CLI vs. React Native CLI (0) | 2022.07.07 |