React Navigation - ParkEunwoo/seoul-smart-app GitHub Wiki
-
expo init
์ผ๋ก ๋ง๋ ํด๋๋ก ๋ค์ด๊ฐ๋ค.
yarn add react-navigation
yarn add react-native-gesture-handler
-
yarn add react-navigation-tabs
-> ์๋จ์ ํญ์ ๋ง๋ค๊ธฐ ์ํด์ yarn add react-native-reanimated
yarn add react-navigation-stack
-
expo install react-native-gesture-handler react-native-reanimated
๋ช ๋ น์ด๋ฅผ ํตํด react-navigation์ ์ค์นํฉ๋๋ค. -
react-navigation์ tab navigation์ ๊ธฐ๋ณธ์ ์ผ๋ก ์คํฌ๋ฆฐ ํ๋จ์ ๋ง๋ค๋๋ก ๋์ด์์ต๋๋ค. ์ ํฌ๋ ์์ด์ดํ๋ ์์ฒ๋ผ ํญ์ ์๋จ์ ๋ง๋ค๊ธฐ ์ํด ์ถ๊ฐ๋ก ๋ ์ค์นํ ๊ฒ์ด ์์ต๋๋ค.
-
ํฐ๋ฏธ๋ ์ฐฝ์์
yarn add react-navigation-tabs
๋ช ๋ น์ด๋ก ์ค์นํด์ฃผ์ธ์. -
๋ค์์ผ๋ก ํฐ๋ฏธ๋์ฐฝ์์
yarn add react-navigation-reanimated
๋ช ๋ น์ด๋ก ์ค์นํด์ฃผ์ธ์.
- App.js ํ์ผ
- components : screen์ ๊ตฌ์ฑํ๋ ์ปดํฌ๋ํธ๋ค์ด ์๋ ํด๋
- screens : ์ฑ์์ ๋ณด์ฌ์ง๋ ํ๋ฉด๋ค์ด ์๋ ํด๋ (๋ฉ์ธ, ์ฅ์, ํ๋..)
- navigation : ํ๋ฉด๋ค์ ๋ค๋น๊ฒ์ด์ ์ผ๋ก ๋ฑ๋กํ๋ ๋ถ๋ถ
- ํ๋ฉด์ ์ฒ์ ๋ก๊ทธ์ธ ํ์ด์ง, ๋ก๊ทธ์ธ ํ ๋ณด์ด๋ ๋ฉ์ธํ์ด์ง-์ฅ์ํ์ด์ง-ํ๋ํ์ด์ง, ์ฅ์ํ์ด์ง์์ detail๋ทฐ ํ์ด์ง๋ก ์ด๋ฃจ์ด์ ธ์์ต๋๋ค.
- ํ๋ฉด์ screens ํด๋์ ๋ง๋ค๋ฉด ๋ฉ๋๋ค.
- LoginScreen.js, MainScreen.js , PlaceScreen.js, PlaceDetailScreen.js, APScreen.js ํ์ผ์ ๋ง๋ค์ด ์ฃผ์ธ์.
LoginScreen.js
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native'
export default function LoginScreen(props) {
return (
<View style={styles.container}>
<Text>It's LoginScreen!</Text>
<TouchableOpacity title="Login" onPress={() => _doLogin(props)}>
<Text>Login</Text>
</TouchableOpacity>
</View>
);
}
//ํ์ด์ง ์ด๋ -> navigation.navigate(์ด๋ํ ํ์ด์ง)
function _doLogin(props){
props.navigation.navigate('MainTabNavigator');
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})
MainScreen.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function MainScreen() {
return (
<View style={styles.container}>
<Text>It's Main!</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})
PlaceScreen.js
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { createStackNavigator } from 'react-navigation-stack';
export default function PlaceScreen(props) {
return (
<View style={styles.container}>
<Text>It's Place!</Text>
<TouchableOpacity title="MovePlaceDetail" onPress={() => _goPlaceDetail(props)}>
<Text>
Move to DetailView
</Text>
</TouchableOpacity>
</View>
);
}
//์ฅ์ํ์ด์ง์์ ์ฅ์๋ํ
์ผํ์ด์ง๋ก ์ด๋
function _goPlaceDetail(props){
props.navigation.navigate('PlaceDetail');
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})
APScreen
...Main๊ณผ ๋์ผ
export default function ActivityProgramScreen() {
return (
<View style={styles.container}>
<Text>It's Activity and Program!</Text>
</View>
);
}
...Main๊ณผ ๋์ผ
- **react-navigation"์ ๋ค๋น๊ฒ์ด์ ์ ๊ตฌํํ๋๋ฐ ์คํ(stack) ๋ค๋น๊ฒ์ดํฐ์ผ๋ก ๊ตฌํํฉ๋๋ค.
- ์ฌ์ฉํ screen๋ค์ stacknavigator์ ๋ฑ๋กํ๊ณ ๋ค์ํ ํจ์๋ค์ ์ด์ฉํด ํ๋จ tab, ์๋จ tab, drawer ๋ฑ์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
- navigation ํด๋์ tab navigation ์ ๋ง๋ค๊ธฐ ์ํด MainTabNavigator.js ํ์ผ์ ๋ง๋ค์ด ์ฃผ์ธ์.
- ์ด๋ ๊ฒ ์ฌ์ฉํ ์คํฌ๋ฆฐ์ stack์ ๋ฑ๋กํ๋ ์ญํ ์ ํ๋ ํจ์๊ฐ createStackNavigator ์ ๋๋ค.
- ์คํ๋ค๋น๊ฒ์ดํฐ์ ๋ฑ๋ก๋ ์คํ(๊ทธ๋ฌ๋๊น ๋ฑ๋ก๋ ์คํฌ๋ฆฐ)๋ค์ ๋ชจ์ createBottomTabNavigator์ ํตํด ํ๋จ tab์ ๋ง๋ค ์ ์์ต๋๋ค.
MainTabNavigator
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
//์คํ๋ค๋น๊ฒ์ด์
์ ๋ฑ๋กํ screen๋ค์ ๋ถ๋ฌ์ค๊ธฐ
import MainScreen from '../screens/MainScreen';
import PlaceScreen from '../screens/PlaceScreen';
import PlaceDetailScreen from '../screens/PlaceDetailScreen'
import APScreen from '../screens/APScreen';
const config = Platform.select({
web: { headerMode: 'screen' },
default: {},
});
//MainStack์ด๋ผ๋ ์ด๋ฆ์ผ๋ก StackNavigator๋ฅผ ๋ง๋ญ๋๋ค.
//์ด ๋, MainScreenํ๋ฉด์ Main์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฑ๋กํฉ๋๋ค.
const MainStack = createStackNavigator(
{
Main: MainScreen,
},
config
);
MainStack.navigationOptions = {
tabBarLabel: 'Main',
};
MainStack.path = '';
//PlaceStack์๋ 2๊ฐ์ง์ ํ๋ฉด์ ๋ฑ๋กํ์ต๋๋ค.
//์๋ํ๋ฉด ์ฅ์ํ์ด์ง์์ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ฅ์์์ธ๋ณด๊ธฐ๋ก ๋์ด๊ฐ์ผํ๊ธฐ ๋๋ฌธ์
๋๋ค.
const PlaceStack = createStackNavigator(
{
Place: PlaceScreen,
PlaceDetail : PlaceDetailScreen,
},
config
);
PlaceStack.navigationOptions = {
tabBarLabel: 'Place',
};
PlaceStack.path = '';
//์ฅ์์์ธ๋ณด๊ธฐ๋ก ๋์ด๊ฐ์ ๋ ํ๋จ ํญ์ด ์๋ณด์ด๋๋ก ํ๋ ๊ธฐ๋ฅ ๊ตฌํ
PlaceStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
const APStack = createStackNavigator(
{
AP: APScreen,
},
config
);
APStack.navigationOptions = {
tabBarLabel: 'AP',
};
APStack.path = '';
//๊ฐ๊ฐ์ ํ๋ฉด๋ค๋ฆฌ ๋ฑ๋ก๋ ์คํ์ผ๋ก tanNavigator๋ผ๋ ํ๋จtab์ ๋ง๋ญ๋๋ค.
const tabNavigator = createBottomTabNavigator({
MainStack,
PlaceStack,
APStack,
});
tabNavigator.path = '';
//ํ๋จ tab์ ๋ง๋ค์์ง๋ง ํ๋จ tab๋ง์ด ์ ์ฒด ํ๋ฉด์ด ์๋๋๋ค.
//๋ฐ๋ผ์, MainNav๋ผ๋ ์ด๋ฆ์ ์ ์ฒดํ๋ฉด ๋์ํ๊ณ tabNavigator๋ฅผ ๊ฐ๋ ์คํ๋ค๋น๊ฒ์ดํฐ๋ฅผ ๋ง๋ค์ด์ผํฉ๋๋ค.
//tabNavigator๋ฅผ exportํ๋ฉด ํ๋จtab๋ง ์๊ธฐ๋ ๊ผด์ด๊ฒ ์ฃ ..!
const MainNav = createStackNavigator({
tabNavigator: {
screen: tabNavigator,
navigationOptions: ({navigation}) => ({
header: null,
})
}
})
export default MainNav;
- ์คํ๋ค๋น๊ฒ์ดํฐ์ ๋ฑ๋ก์ ํ์ผ๋ฉด ๊ทธ๊ฒ์ ์ปดํฌ๋ํธ๋ก ๋ฐํํด์ผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ด ๋ ์ฌ์ฉํ๋ ๊ฒ์ด createAppContainer ์ ๋๋ค.
- ์ด๋ฅผ ์ํด navigation ํด๋์ AppNavigator.js ํ์ผ์ ๋ง๋ค์ด ์ฃผ์ธ์.
- ์ ํฌ๋ ๋ก๊ทธ์ธ ํ๋ฉด์ด ๋จผ์ ๋ณด์ด๊ณ ๋ก๊ทธ์ธํ๋ฉด์์ ๋ก๊ทธ์ธ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ ์ฒดํ๋ฉด์ด ๋ณด์ด๋๋ก ๊ตฌํํ๊ธฐ ์ํด createSwitchNavigatorํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- createSwitchNavigator๋ ์คํ์ ๊ฐ์ฅ ๋ฐ์ ์๋ ํ๋ฉด์ ๋ง๊ทธ๋๋ก switch! ํด์ฃผ๋ ํจ์์ ๋๋ค. ์คํ์ ๊ฐ์ฅ ๋ฐ์ ์๋ ํ๋ฉด์ด๋ผ๋ ๊ฒ์ ๋งจ ์ฒ์ ๋ณด์ฌ์ง๋ ํ๋ฉด์ด๊ฒ ์ฃ ..!
- intialRouteName์ ํตํด ์ฒ์ ๋ณด์ฌ์ง๋ ํ๋ฉด์ ์ ํ ์ ์์ต๋๋ค.
- ์ฆ, ๋งจ ์ฒ์ ๋ก๊ทธ์ธ ํ๋ฉด์ด ๋ณด์ผ ๋๋ ์คํ์ ๊ฐ์ฅ ๋ฐ์ด loginscreen์ด์ง๋ง
LoginScreen
<TouchableOpacity title="Login" onPress={() => _doLogin(props)}>
<Text>Login</Text>
</TouchableOpacity>
...
function _doLogin(props){
props.navigation.navigate('MainTabNavigator');
}
- ๋ก๊ทธ์ธ์ด ๋๋๊ณ ์ ์ฒดํ๋ฉด์ผ๋ก ์ด๋ํ๋ฉด ์คํ์ ๊ฐ์ฅ ๋ฐ์ ์๋ ํ๋ฉด์ด MainTabNavigator๊ฐ ๋ฉ๋๋ค.
AppNavigator
import React from 'react';
import LoginScreen from '../screens/LoginScreen';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import MainTabNavigator from './MainTabNavigator';
export default createAppContainer(
createSwitchNavigator({
LoginScreen,
MainTabNavigator,
},
{
initialRouteName: 'LoginScreen',
}
)
);
- ์ค์ ํ๋ฉด์ ๋์ค๋ ๊ฒ๋ค์ App.js์ ๋ฃ์ด์ค์ผ ํฉ๋๋ค.
App.js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import AppNavigator from './navigation/AppNavigator';
export default function App() {
return (
<AppNavigator/>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
- react-navigation์ ํ๋ฉด(screen)๋ค์ ์คํ๋ค๋น๊ฒ์ดํฐ(stacknavigator)๋ก ๊ด๋ฆฌํฉ๋๋ค. ์ฆ, ์๋ก์ด ํ๋ฉด์ ๋ค์ด๊ฐ ์๋ก ์คํ์ ์์ธ๋ค..๋ผ๊ณ ์๊ฐํ๋ฉด ๋ ๊ฒ ๊ฐ์์!
- ๋ฐ๋ผ์ ์ฌ์ฉํ ํ๋ฉด๋ค์ createStackNavigator๋ก ์คํ๋ค๋น๊ฒ์ดํฐ์ ๋ฑ๋กํด์ผํฉ๋๋ค. ํ์ด์ง ์ด๋(navigation.navigate)์ ํ๋ฉด์ด ์คํ์ ๋ฑ๋ก๋ ํ๋ฉด์ด์ด์ผ ์ด๋์ด ๊ฐ๋ฅํฉ๋๋ค!!
- ๋ฑ๋ก๋ ํ๋ฉด๋ค์ createBottomTabNavigator์ ๊ฐ์ ํจ์๋ค๋ก ํ๋จํญ, ํค๋, ๋๋ก์ ๋ฑ๋ฑ์ ๋ง๋ค ์ ์์ต๋๋ค.
- ๋ง๋ ํ์๋ ์ปดํฌ๋ํธ๋ก ๋ฐํํด์ผ ์ฌ์ฉํ ์ ์์ต๋๋ค. createAppContainer๋ฅผ ์ฌ์ฉํด์ผํฉ๋๋ค.
- ํ์ด์ง ๊ฐ ์ด๋
์คํ๋ค๋น๊ฒ์ดํฐ์ ๋ฑ๋ก๋ ๋ชจ๋ screen๋ค์ navigation prop์ ๊ฐ์ต๋๋ค. navigation์ ์๋ ๋ฉ์๋ navigate๋ฅผ ํตํด ์ด๋ํ ์ ์์ต๋๋ค. ๊ทธ ์ธ์๋ push, goBack, popToTop ๋ฑ์ด ์์ต๋๋ค. ๋ฉ์๋์ ์ฒซ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ด๋ํ ํ์ด์ง๋ฅผ, ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก๋ ์ด๋ค ๊ฐ์ ๊ฐ์ฒด ํํ๋ก ์ ๋ฌํ ์ ์์ต๋๋ค.
- ์์ธํ์ด์ง ๋ค์ด๊ฐ ๋ ํ๋จtab ์์ ๊ธฐ
๋ค์ํ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค..์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์! Navigation options resolution
์ฌ๊ธฐ๋ถํฐ๋ ๊ณต์๋ฌธ์๋ฅผ ๋ณด๊ณ ์ ๋ฆฌํ๊ฑฐ๋ผ ์ฐธ๊ณ ํด์ฃผ์ธ์!
- ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ๋ฐํ
- createStackNavigator๋ก ๋ง๋ค์ด์ง ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์์ ์ด ์ปดํฌ๋ํธ๋ฅผ ๋ฐํ
<์์>
import React from 'react';
import { View, Text } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
}
class DetailsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
}
const AppNavigator = createStackNavigator(
{
Home: HomeScreen, /*Homescreen ์ปดํฌ๋ํธ๋ฅผ ๋ค๋น๊ฒ์ดํฐ์ ๋ฑ๋ก*/
Details: DetailsScreen, /*DetailsScreen ์ปดํฌ๋ํธ๋ฅผ ๋ค๋น๊ฒ์ดํฐ์ ๋ฑ๋ก*/
},
{
initialRouteName: 'Home',
}
);
/*
Home๊ณผ Details์ด๋ผ๋ 2๊ฐ์ route๊ฐ ์์ฑ๋์๋ค.
Home route(key)๋ HomeScreen ์ปดํฌ๋ํธ(value)์ ํด๋นํ๊ณ , Details route(key) ๋ DetailsScreen(value)์ ํด๋น*/
const AppContainer = createAppContainer(AppNavigator);
/*๋ค๋น๊ฒ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ createAppContainer๋ก ๋ฐํํด์ผ ํ๋ค*/
export default class App extends React.Component {
render() {
return <AppContainer />; /*AppContainer ์ปดํฌ๋ํธ๋ฅผ ๋ฐํํ๋ค*/
}
}
- navigate ํจ์ : ์ด screen์ผ๋ก ์ด๋ํ๋ผ
<์์>
import React from 'react';
import { Button, View, Text } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
- this.props.navigation : stack ๋ด๋น๊ฒ์ดํฐ์ ๋ชจ๋ screen ์ปดํฌ๋ํธ๋ก ์ ๋ฌ๋จ
- navigate('Details') : 'Detail' route๋ก ์ด๋
- push ํจ์
<์์>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.push('Details')}
/>
- navigate ํจ์๋ ๋ถ๋ฅธ route๊ฐ ์๋ก์ด ๊ฒ(stack์ ์์ ๋)์ผ ๋๋ง stack์ route๋ฅผ ์ถ๊ฐํจ
- push ํจ์๋ ์๊ด์์ด ๊ณ์ route๋ฅผ ์ถ๊ฐํ ์ ์์
์๋ฅผ ๋ค์ด์, ํ์ฌ ํ๋ฉด์์ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ์ ๋ฐ์์ ์ธ๋ถ์ ์ธ ๋ค๋ฅธ ํ๋ฉด์ ์ถ๊ฐํ๊ณ ์ถ์ ๊ฒฝ์ฐ, (์์ ์์์๋ ์ถ๊ฐํ ๊ฐ์ด ์์ต๋๋ค) navigate๋ฅผ ์ฌ์ฉํ๋ฉด stack์ ์ด๋ฏธ ์๋ ํ๋ฉด์ด๋ฏ๋ก ์ถ๊ฐ๋์ง ์์ต๋๋ค. ๊ทธ๋ด ๋๋ push!
- goBack ํจ์
-
๋ค๋ก๊ฐ๊ธฐ ๋ฒํผ์ ํค๋ ๋ฐ์ ์๋์ ์ผ๋ก ๋ณด์ฌ์ง์ง๋ง ์ง์ ํธ๋ค๋งํ๊ณ ์ถ๋ค๋ฉด
this.props.navigation.push('Route ์ด๋ฆ')
๋ผ๊ณ ์ค์ ํ๋ฉด ๋จ -
์ฒ์ ํ๋ฉด(๋ฉ์ธ ํ๋ฉด)์ผ๋ก ๋์๊ฐ๋ ค๋ฉด navigate ํจ์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋
this.props.navigation.popToTop()
์ ์ฌ์ฉ -> stack์์ ์ฒ์ ํ๋ฉด์ผ๋ก ๋์๊ฐ๊ฒ ํด์ค
- ์ ๋ฌ: ํจ์๋ฅผ navigate ํจ์์ 2๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ ๊ฒ์ ๊ฐ์ฒด ํํ๋ก ๋ฃ์ด์ค
this.props.navigation.navigate('route ์ด๋ฆ', { ์ ๋ฌ๋ด์ฉ })
- ์ฝ๊ธฐ:
this.props.navigation.getParam('ํ๋ผ๋ฏธํฐ ์ด๋ฆ','default value')
<์์>
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => {
/* Details route๋ก ๋๊ฒจ์ค ๋ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ์ ๋ฃ์ด์ค๋ค */
this.props.navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
render() {
/* ํ๋ผ๋ฏธํฐ ๋ด์ฉ์ ๊ฐ์ ธ์จ๋ค */
const { navigation } = this.props;
const itemId = navigation.getParam('itemId', 'NO-ID');
const otherParam = navigation.getParam('otherParam', 'some default value');
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
title="Go to Details... again"
onPress={() =>
this.props.navigation.push('Details', {
itemId: Math.floor(Math.random() * 100),
})
}
/>
<Button
title="Go to Home"
onPress={() => this.props.navigation.navigate('Home')}
/>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
);
}
}
์์ง ๋ง์ด ๋ชป์จ์.. ๊ณ์ ์ถ๊ฐํ๊ฒ ์ต๋๋คใ ใ