React-Native 초기 세팅
공식문서 Getting Started의 Xcode & CocoaPods 단계까지 설정한 후 진행하시면 됩니다.
Getting Started · React Native
1. RN Project 생성
프로젝트를 생성해 봅시다. 공식 문서에는 npx react-native init AwesomeProject 를 쓰라고 나와있지만
저는 react-native init 명령어를 통해 생성하겠습니다. ( 이미 react-native가 설치 되어 있기 때문입니다.)
react-native init test_rn
cd test_rn
react-native run-ios
시뮬레이터에 정상적인 화면이 나온다면 bundle server와 시뮬레이터를 끄고 다시 진행합니다.
프로젝트 구조는 위와 같이 구성합니다.
2. React Navigation 구축
SPA인 리액트의 특성상 Routing을 위해선 다른 라이브러리가 필요합니다.
대표적인 라이브러리로는 React Native Navigation과 React Navigation이 있습니다. 저희는 R-Nav를 사용합니다. 이유는
-
가장 널리 사용 되고 활발하게 개발 된 라이브러리
-
React Native팀이 권장 하는 솔루션
-
Facebook이 가장 많이 추진하는 커뮤니티 솔루션
React Navigation · Routing and navigation for your React Native apps
공식 문서의 Getting started를 그대로 진행 합니다.
npm install @react-navigation/native
npm install react-native-reanimated react-native-gesture-handler
react-native-screens react-native-safe-area-context
@react-native-community/masked-view
예전에는 하나의 Package였지만, 버전이 올라감에 따라 나눠 지게 되어서 설치 과정이 늘어났습니다.
npm이 다 되고 나면 linking을 해야 합니다. RN 0.6x 버전 이상부터는 Auto Linking을 지원하기 때문에 link 과정이 필요 없고 아래 처럼 진행하면 됩니다.
IOS
cd ios; pod install; cd ..
Android
android/app/build.gradle 파일에 추가
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'
여기 까지 진행 후 실행을 해보시면 정상적으로 작동이 됩니다.
3. Stack, Bottom Tab, Drawer Navigation
R-Nav 업데이트로 인해 기존에 포함되어 있던 Stack과 Bottom Tab, Drawer Navigation들도 따로 설치 해 야 합니다.
npm install @react-navigation/bottom-tabs
npm install @react-navigation/stack
npm install @react-navigation/drawer
4. Navigation Example
지금부터 Bottom Tab과 Drawer Menu를 가진 Stack App을 하나 생성 해보겠습니다.
밑에 예제는 router.js 파일로 관리 하는 방법입니다.
// App.js
import * as React from "react";
import Router from "./src/settings/router";
export default function App() {
return (
<>
<Router />
</>
);
}
// src/settings/router.js
import * as React from "react";
import { Button, View, Text } from "react-native";
import { createStackNavigator } from "@react-navigation/stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { createDrawerNavigator } from "@react-navigation/drawer";
import { NavigationContainer } from "@react-navigation/native";
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Tab = createBottomTabNavigator();
function SplashScreen({ navigation }) {
return (
<View style=>
<Button
onPress={() => navigation.navigate("Drawer")}
title="Main으로 이동"
/>
</View>
);
}
function HomeScreen({ navigation }) {
return (
<View style=>
<Button
onPress={() => navigation.navigate("Notifications")}
title="다른 화면으로 이동"
/>
</View>
);
}
function NotificationsScreen({ navigation }) {
return (
<View style=>
<Button onPress={() => navigation.navigate("Tab")} title="Go back home" />
</View>
);
}
function SettingsScreen() {
return (
<View style=>
<Text>Settings!</Text>
</View>
);
}
function MyDrawer() {
return (
<Drawer.Navigator>
<Stack.Screen name="Tab" component={MyTab} />
<Drawer.Screen name="SettingsScreen" component={SettingsScreen} />
</Drawer.Navigator>
);
}
function MyTab() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
export default function Router() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Splash" component={SplashScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Notifications" component={NotificationsScreen} />
<Stack.Screen name="Tab" component={MyTab} />
<Stack.Screen name="Drawer" component={MyDrawer} />
</Stack.Navigator>
</NavigationContainer>
);
}
구체적인 사용법 ( Header, Tab icon 등)은 공식 문서를 참고하시면 됩니다.
5. MobX
windevel에서는 상태 관리 라이브러리로 mobx를 사용하고 있습니다.
지금부터는 test app에 mobx를 적용하여 상태 관리를 해보도록 하겠습니다.
npm install mobx --save
npm install mobx-react --save
npm install @babel/plugin-proposal-decorators --save
mobx와 mobx-react를 설치합니다.
plugin-proposal-decorators를 설치하는 이유는 decorator문법으로 편하게 사용하기 위해서 입니다.
babel.config.js 파일을 아래와 같이 수정합니다.
module.exports = {
presets: ["module:metro-react-native-babel-preset"],
plugins: [
[
"@babel/plugin-proposal-decorators",
{
legacy: true,
},
],
],
};
settings 폴더 밑에 stores 폴더를 만듭시다.
mkdir stores
cd stores
stores 폴더 밑에 index.js , user.js 파일을 만들어서 간단한 유저 정보를 만듭시다.
// index.js
import UserStore from "./user";
class RootStore {
constructor() {
this.userStore = new UserStore(this);
}
}
export default new RootStore();
// user.js
import { observable, action } from "mobx";
export default class UserStore {
constructor(rootStore) {
this.rootStore = rootStore;
}
@observable user_name = "김한솔";
@action
userNameChange(data) {
this.user_name = data;
}
}
App.js 를 Mobx Provider로 래핑해야 합니다.
// App.js
import * as React from "react";
import Router from "./src/settings/router";
import { Provider } from "mobx-react";
import rootStore from "./src/settings/stores";
export default function App() {
return (
<Provider {...rootStore}>
<Router />
</Provider>
);
}
이제 mobx를 쓰고 싶은 화면에서 mobx를 쓰면 됩니다.
Splash 화면을 router에서 빼서 새로 만듭시다.
데코레이터를 편하게 사용하기 위해 class component를 사용합니다.
// pages/Splash.js
import React, { Component } from "react";
import { Button, View } from "react-native";
import { observer, inject } from "mobx-react";
@inject("userStore")
@observer
export default class SplashScreen extends Component {
render() {
return (
<View style=>
<Button
onPress={() => this.props.navigation.navigate("Drawer")}
title="Main으로 이동"
/>
<Button
onPress={() => navigation.navigate("Notifications")}
title={this.props.userStore.user_name}
/>
</View>
);
}
}
router.js 파일도 아래와 같이 수정합니다.
// router.js
import * as React from "react";
import { Button, View, Text } from "react-native";
import { createStackNavigator } from "@react-navigation/stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { createDrawerNavigator } from "@react-navigation/drawer";
import { NavigationContainer } from "@react-navigation/native";
import SplashScreen from "../pages/Splash";
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Tab = createBottomTabNavigator();
const Splash = SplashScreen;
function HomeScreen({ navigation }) {
return (
<View style=>
<Button
onPress={() => navigation.navigate("Notifications")}
title="다른 화면으로 이동"
/>
</View>
);
}
function NotificationsScreen({ navigation }) {
return (
<View style=>
<Button onPress={() => navigation.navigate("Tab")} title="Go back home" />
</View>
);
}
function SettingsScreen() {
return (
<View style=>
<Text>Settings!</Text>
</View>
);
}
function MyDrawer() {
return (
<Drawer.Navigator>
<Stack.Screen name="Tab" component={MyTab} />
<Drawer.Screen name="SettingsScreen" component={SettingsScreen} />
</Drawer.Navigator>
);
}
function MyTab() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
export default function Router() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Splash" component={Splash} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Notifications" component={NotificationsScreen} />
<Stack.Screen name="Tab" component={MyTab} />
<Stack.Screen name="Drawer" component={MyDrawer} />
</Stack.Navigator>
</NavigationContainer>
);
}
실행하면 mobx props를 확인할 수 있습니다.
버튼을 누르면 user_name이 바뀌게 해보겠습니다.
<Button
onPress={() => this.props.userStore.userNameChange("정기열")}
title={this.props.userStore.user_name}
/>
버튼을 누르면 확인할 수 있습니다.
소스는 아래 리포지토리에서 확인이 가능합니다.