[React Native] 신규 프로젝트 생성 및 셋업

2022. 5. 20. 03:21React Native/Intermediate

 

 


 


 

 


1. 새 프로젝트 생성 및 라이브러리 설치

react-native init [project-name]
npm install --save axios@0.18.0 react-redux@6.0.1 redux@4.0.1 redux-promise@0.6.0

 

axio - promise API 를 활용하는 http 비동기 통신 라이브러리, 백엔드를 다룰 예정으로 필요

react-redux - react, redux UI binding

redux - 사용

redux-promise - 미들웨어 사용 위해 필요

 

npm install @react-navigation/native

navigation 설치

 

npm install react-native-gesture-handler

navigation 관련 dependency 설치

 

npx pod-install ios

dependency 들을 react native와 linking 시키는 명령어

 

package.json을 보면 react-native-gesture-handler가 있는데 이건 entry 파일에서 import 하는 추가 코딩 필요

 


2. Redux 셋업

프로젝트 폴더 내에 app 폴더를 만들고 app 폴더 안에 store 폴더를 만든다. 이 /app/store 폴더 안에 actions와 reducer라는 폴더를 만든다. 

 

reducers 폴더 안에 index.js 라는 파일을 만들고 sample_reducer.js 라는 파일을 만들자. 그리고 store라는 폴더 안데 types.js라는 라일을 만들어 타입을 관리하는 파일을 만든다. app 폴더 내에 index.js라는 파일을 만들어 기존의 App.js 파일의 내용을 복붙해오고 App.js 파일을 삭제해 주자.

이렇게 하면 App.js 파일이 없어지면서 앱을 기동시켜주는 파일이 없어져 에러가 생긴다. 그럼 앱을 기동시켜주는 파일을 수정해주기 위해 루트 폴더 내의 index.js로 가자.

 

앱을 import 하는 경로를 우선 수정해주자. 그리고 redux 관련 모듈을 import 해주자, store를 생성하기 위해 createStore, 미들웨어의 사용을 위해 applyMiddleware를 import 한다. 그리고 compose를 import 해주는데 compose의 역할은 다음과 같다.

store를 생성할 때 몇 가지 미들웨어를 조합해서 만들 것인데 store interface를 바꿔서 새로운 store 생산자를 반환하는 고차함수를 enhancer 라고 한다. compose는 여러 store enhancer를 순차적으로 적용시키기 위한 함수형 프로그래밍 유틸리티이다. 여러 store enhancer 조합을 만들어주는 역할을 한다. 

 

그 다음 Provider라는 것을 react-redux에서 import 해주자. Provider란 store를 react native로 패싱해주기 위해서 필요하다. store를 생성해주어도 react native 컴포넌트는 스스로 store를 찾지 못한다. 그래서 react native 컴포넌트한테 store를 알려줄 필요가 있고 우리 앱 전체를 store를 provide하는 Provider로 감싸준다.

 

그리고 redux-promise에서 promissMiddleware를 import 해주자. 이건 비동기처리가 필요한 action creator 사용을 위해 필요하다.

 

그리고 AppRegistry쪽을 보자.

현재 App의 컴포넌트를 기동시키도록 되어 있는데 우리는 redux를 활용할 거라 appRedux로 바꿔주고 appRedux 라는 함수를 만들어주자. 이 함수 안에서 store를 만들어줄 것이다. 앱 전체를 Provider로 감싸주기 위해 Provider 안에 App을 넣어주고 Provider에 store를 만들어 주는 함수 createStoreWithMiddleware를 넣자. 이 함수는 createStore([reducer],[enhancer]) 를 갖는다. 

 

그럼 큰 윤곽을 잡았고 store를 꾸며보자. /app/store/reducers/index.js로 가자. 여러 reducer를 사용할 수 있기 때문에 이 reducer들을 하나로 묶어주는 기능을 하는 combineReducers라는 것을 redux 모듈에서 가져오자. 그리고 sample_reducer.js에 작성할 reducer 함수를 import 하자. 그리고 rootReducer 함수를 만들고 combineReducers를 이용해서 Sample를 넣어주자. 앞으로 만들어갈 reducer들을 여기서 한번에 묶을 것이다.

 

그럼 sample_reducer.js로 가서 reducer함수를 작성하자. reducer는 state, action 인자를 받아와서 switch 문으로 분기된 로직을 처리하고 새로운 state를 반환했다. 함수를 만들어 인자로 state, action을 넣어주고 switch 문을 작성하자.

 

다시 루트의 index.js로 가자. reducer를 작성한 이유는 store를 마저 꾸미기 위함인데 reducers라는 이름으로 아까 만든 /app/store/reducers를 import 해준다. 그리고 이걸 아까 만들어둔 createStoreWithMiddleware 의 인자 reducers 부분에 넣어주자. 그리고 createStoreWithMiddleware 이 함수의 2번째 인자는 composeEnhancers라는 enhancer를 넣어주자. Redux 개발자 도구와 미들웨어를 사용하기 위해서 window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ 라고 작성해주자. 이건 redux 개발자 도구와 미들웨어를 같이 사용하기 위해 필요한 것으로 크롬 확장프로그램에 작성되어있는 자바스크립트 함수이다. 그리고 일반 compose도 함께 쓰기 위해서 || compose 도 써주자. 그리고 이 enhancer의 인자로는 미들웨어를 쓰기 위해서 applyMiddleware를 넣을 것이고 또 이 인자로 promiseMiddleware를 넣어주자.

 

그럼 redux 셋업이 끝난다.

 

디렉토리 구조

├─ app
│  ├─ index.js
│  └─ store
│     ├─ actions
│     ├─ reducers
│     │  ├─ index.js
│     │  └─ sample_reducer.js
│     └─ types.js
├─ app.json
├─ index.js
/**
 * index.js
 */

import React from 'react';
import {AppRegistry} from 'react-native';
import App from './app/index';
import {name as appName} from './app.json';

import {createStore, applyMiddleware, compose} from 'redux';
import {Provider} from 'react-redux';
import promissMiddleware from 'redux-promise';
import reducers from './app/store/reducers';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const createStoreMiddleware = createStore(
  reducers,
  composeEnhancers(applyMiddleware(promissMiddleware)),
);

const appRedux = () => (
  <Provider store={createStoreMiddleware}>
    <App />
  </Provider>
);

AppRegistry.registerComponent(appName, () => appRedux);
/**
 * /app/index.js
 */

import 'react-native-gesture-handler';

import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';

const App = () => {
  return (
    <NavigationContainer>
      <View>
        <Text>Hello World</Text>
      </View>
    </NavigationContainer>
  );
};

const styles = StyleSheet.create({});

export default App;
// /app/store/reducers/index.js
import {combineReducers} from 'redux';
import Sample from './sample_reducer';

const rootReducer = combineReducers({
  Sample,
});

export default rootReducer;
// /app/store/reducers/samples_reducer.js
export default function (state = {}, action) {
  switch (action.type) {
    case 'SAMPLE':
      return state;

    default:
      return state;
  }
}

3. React Navigation 셋업

npm install @react-navigation/stack @react-navigation/bottom-tabs
npm install react-native-reanimated react-native-safe-area-context react-native-screens @react-native-community/masked-view
cd ios && pod install

 

app 아래 components 폴더를 만들고 화면 파일을 만들기 위해 각각의 디렉토리를 만들어주자. 화면을 3개를 만들거라 3개의 디렉토리를 만들자. 각각의 디렉토리에 index.js를 만들어 준다. 그리고 navigator를 설계할 파일을 만들건데 이건 app 폴더 아래 바로 roots.js로 만들자.

 

설계할 navigator

/*
    Stack Navigator
        - Stack Screen A

    Stack Navigator
        - Tab Navigator
            - Tab Screen B
            - Tab Screen C

*/
├─ app
│  ├─ components
│  │  ├─ auth
│  │  │  └─ index.js
│  │  ├─ diary
│  │  │  └─ index.js
│  │  └─ news
│  │     └─ index.js
│  ├─ index.js
│  ├─ routes.js
│  └─ store
│     ├─ actions
│     ├─ reducers
│     │  ├─ index.js
│     │  └─ sample_reducer.js
│     └─ types.js
├─ app.json
├─ index.js

로그인 X Stack Screen A (SignIn 화면)

로그인 시 Tab Navitoar (Diary, News 화면)

 

/**
 * /app/index.js
 */

import 'react-native-gesture-handler';

import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {RootNavigator} from './routes';
const App = () => {
  return (
    <NavigationContainer>
      <RootNavigator />
    </NavigationContainer>
  );
};

const styles = StyleSheet.create({});

export default App;
// /app/routes.js

import React, {Component} from 'react';

import {createStackNavigator} from '@react-navigation/stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';

//Screens
import SignIn from './components/auth';
import Diary from './components/diary';
import News from './components/news';

const AuthStack = createStackNavigator();
const MainScreenTab = createBottomTabNavigator();

/*
    Stack Navigator
        - Stack Screen A

    Stack Navigator
        - Tab Navigator
            - Tab Screen B
            - Tab Screen C

*/

const isLoggedIn = true;
const AppTabComponent = () => {
  return (
    <MainScreenTab.Navigator>
      <MainScreenTab.Screen name="Diary" component={Diary} />
      <MainScreenTab.Screen name="News" component={News} />
    </MainScreenTab.Navigator>
  );
};
export const RootNavigator = () => {
  return (
    <AuthStack.Navigator>
      {isLoggedIn ? (
        <AuthStack.Screen name="Main" component={AppTabComponent} />
      ) : (
        <AuthStack.Screen name="SignIn" component={SignIn} />
      )}
    </AuthStack.Navigator>
  );
};
// /app/components/auth/index.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';

const AuthComponent = () => {
  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <Text>Auth Screen</Text>
    </View>
  );
};

const styles = StyleSheet.create({});

export default AuthComponent;
// /app/components/diary/index.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';

const DiaryComponent = () => {
  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <Text>Diary Screen</Text>
    </View>
  );
};

const styles = StyleSheet.create({});

export default DiaryComponent;
// /app/components/news/index.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';

const NewsComponent = () => {
  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <Text>News Screen</Text>
    </View>
  );
};

const styles = StyleSheet.create({});

export default NewsComponent;

참고 자료

https://www.inflearn.com/course/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EC%A4%91%EA%B8%89/dashboard

 

iOS/Android 앱 개발을 위한 실전 React Native - Intermediate - 인프런 | 강의

React Native 기반 모바일 앱 개발을 위한 중급 강의입니다. 프론트엔드의 심화내용 학습 뿐만 아니라 Firebase 기반의 백엔드 내용까지 함께 배우면서, 서버 연동/ 로그인/ 데이터 송수신/ 공공API 활

www.inflearn.com