본문 바로가기

Lecture/React Native

2021-07-05 :: React Native 개발환경 + 기본

01 리액트 네이티브 개발 환경 갖추기

모바일 앱 개발에서 네이티브라는 단어는 운영체제를 만들 때 사용한 프로그래밍 언어와 똑같은 언어로 만든이라는 뜻이다. 안드로이드는 자바로, iOS에서는 Objective-C로 만든 앱을 네이티브 앱이라고 한다.

리액트 네이티브는 크로스플랫폼 개발 프레임워크이며, 네이티브 파트와 자바스크립트 파트로 나누어진다. 

브릿지 방식

 

안드로이드 앱은 자바로 구현된 안드로이드 프레임워크를, iOS 앱은 Objective-C로 구현된 iOS UIKit 프레임워크를 사용하여 만든다. 두 프레임워크 모두 'View'자가 들어간 많은 클래스를 제공한다. 리액트 네이티브는 웹 브라우저에서 자바스크립트 엔진 부분만 떼어 내어 자바스크립트 코드로 구현된 'View' 클래스를 네이티브 쪽 안드로이드 프레임워크 또는 UIKit 프레임워크의 'View' 클래스 호출로 연결하는 방식으로 작동한다. 이를 브릿지 방식이라고 한다. p.15

 

리엑트 네이티브 개발 환경은 기본적으로 Node.js 개발 환경과 같다.

개발환경을 다 구축한 후 메트로서버는 npm start로 실행한다.

02 리액트 네이티브 기본 다지기

02-1 리액트 네이티브 프레임워크의 작동 원리

웹 브라우저는 HTML 문서를 만나면 파싱 과정을 거쳐 다음과 같은 형태의 자바스크립트 객체 구조를 만든다. 비록 웹 브라우저는 <div>. <h1>과 같은 HTML형태로 보여주지만 자바스크립트 코드 관점에서는 <div>는 HTMLDivElement 클래스의 인스턴스이다. 이 HTMLDivElement와 같은 클래스를 DOM이라 부르고 DOM 클래스의 인스턴스를 DOM 객체라고 한다. 브라우저가 HTML을 파싱하여 자바스크립트 DOM 구조로 만드는 것을 렌더링이라 한다.

 

가상 DOM 구조는 리액트 코드가 생성한 자바스크립트 객체 구조이다. 리액트는 특정 시점에서 이 가상 DOM 구조를 물리 DOM 구조로 만드는데, 이를 리액트가 렌더링한다라고 하고 이 기능을 수행하는 패키지를 렌더러renderer라고 한다.

 

리액트는 가상 DOM 구조를 react-dom이란 렌더러 패키지를 사용하여 물리 DOM 구조로 렌더링하는 방식으로 동작하는 프레임워크이다. 이와는 달리 리액트 네이티브는 react-native라는 렌더러 패키지를 사용하여 렌더링하는 방식으로 동작하는 프레임워크이다. 리액트에서는 react-dom 렌더러를 DOM 렌더러라고 하고 react-native 렌더러를 네이티브 렌더러라 한다.

네이티브 렌더러는 리액트 요소를 안드로이드 프레임워크나 iOS용 UIKit 프레임워크의 화면 UI 객체로 바꿔주는 역할을 한다.

 

리액트 네이티브 앱을 폰에 설치하고 실행하면 리액트 네이티브의 네이티브 모듈이 실행되면서 네이티브를 담당하는 UI스레드와 App.tsx와 같은 자바스크립트 코드를 실행하는 자바스크립트 엔진 스레드 2개가 동시에 동작한다. 이 두 스레드는 서로 렌더링과 관련된 데이터를 주고받는다. 사용자가 화면을 터치하면 UI 스레드는 이 내용을 자바스크립트 쪽 스레드엥 이벤트 형태로 넘긴다. 그리고 이런 방식으로 동작하는 프레임워크를 브리지방식 프레임워크라 한다. 리액트 네이티브 앱은 다중 스레드 앱이다.

 

네이티브, 즉 UI스레드에서 동작하는 부분을 따로 설치 해주어야 한다.

npx react-native link, npx pod-install

 

React.createElement API가 하는 일

리액트와 리액트 네이티브에서 React.createElement API는 가장 저수준 기능으로서 가상 DOM 객체를 생성한다.

물리 DOM 객체를 생성하는 과정을 아래와 같다. 아래 코드는 DOM 객체 생성, 렌더링 과정이다.

const pElement = document.createElement('p')
pElement.innerText = 'Hello JavaScript world!'
document.body.appendChild(pElement)

위의 document.createElement는 물리 DOM 객체를 생성한다면 React.createElement는 가상 DOM 객체를 생성한다.

 

리액트 네이티브 렌더러는 네이티브에서 동작하므로 다음처럼 가장 DOM 객체를 네이티브로 넘겨주는 방식으로 동작한다.

export default function App() {
	const textElement = React.createElement(Text, null, 'Hello world!')
    return textElement
}

npm run android는 안드로이드 앱 빌드 명령을 실행한다.

명령 의미
npm i package.json 파일에 명시된 패키지를 node_modules 디렉터리에 설치한다.
npx pod-install C 계열 언어는 원격 저장소에서 패키지를 내려받아 설치하는 기능이 없다. 따라서 pod 프로그램을 실행하여 원격 저장소에서 필요한 패키지를 내려받아 로컬에 설치해야 한다.
npm start 에뮬레이터를 실행하기 전 npm start 명령을 통해 메트로 서버를 실행해야 한다. 이를 통해 앱이 처음 실행될 때 서버로부터 ES5 JS코드를 내려받을 수 있다.
npm run android 안드로이드 스튜디오의 빌드 명령을 실행하고 빌드한 앱을 에뮬레이터에 설치하고 실행한다. 
npm run ios Xcode의 빌드 명령을 시ㅣ리행하고 빌드한 앱을 시뮬레이터에 설치하고 실행한다. 

02-2 JSX 구문 탐구하기

ESNext 자바스크립트 컴파일러인 바벨은 플러그인 구조로 동작한다. 바벨은 ESNext 자바스크립트 코드를 만나면 수십 개의 플러그인이 차례로 동작하여 특정 ESNext 구문을 플러그인으로 보낸다. 그러면 수십 개의 바벨 플러그인은 ES5 자바스크립트 코드로 컴파일 한다. 리엑트 네이티브 프로젝트에서는 metro-react-native babel-preset이라는 패키지를 사용한다.

 

표현식과 실행문
표현식이란 return 키워드 없이 어떤 값을 반환하는 코드를 말한다. number, boolean, string처럼 값으로 평가하는 어떤 것을 뜻한다.

실행문이란 표현식의 반대되는 것으로 if, switch/case, for문으로 JSX코드 안에서는 사용하지 못한다.

따라서 실행문인 조건문을 JSX에 적용하고 싶다면 JSX문 밖에 두거나 다음과 같이 단축 평가 형태로 구현하면 된다.

{isRender && <Component/>} // 앞 값이 참이면 뒤에 컴포넌트가 렌더링 된다.

02-3 컴포넌트와 속성 이해하기

faker는 더미 데이터를 만드는 패키지이다. 

JSON.stringify(객체, null, 2)는 2개의 공백 문자를 속상값에 붙여 객체를 문자열로 변경하는 함수이다.

number 타입을 속성으로 전달할 때는 중괄호를 사용한다. age={22}

 

지금까지 리액트 네이티브가 제공하는 Text 컴포넌트를 사용하여 화면에 텍스트를 렌더링했다. 리액트 네이티브가 제공하는 서비스에는 크게 Text와 같은 코어 컴포넌트와 Platform, Alert와 같은 API 두 가지가 있다. 코어 컴포넌트는 화면에 어떤 내용을 렌더링할 때 사용되고, API는 폰의 하드웨어나 운영체제가 제공하는 기능이 필요할 때 사용한다.

 

함수의 타입 정의를 확인하는 가장 쉬운 방법은 함수 이름을 클릭하고 우클릭한 뒤 정의로 이동을 실행하는 것이다. createElement함수를 예로 들어 설명하자면, type 변수의 타입 주석 부분에서 FunctionComponent<P>와 같은 제너릭 타입을 볼 수 있다. 여기서 타입 변수 P는 Property의 첫 글자이고, Function Component는 이름이 너무 길므로 react 패키지에서 더 짧은 이름인 FC 타입을 제공한다.

 

TS import type 구문

FC타입에서 import type 구문을 사용한다. 타입은 TS코드를 JS코드로 컴파일할 때만 필요한 정보이다. 컴파일 이후에는 타입 관련 내용은 JS코드에서 사라진다. 이런 이유로 앞 코드에서 FC는 컴파일되면 완전히 사라지는 정보이므로 import type 구문을 사용한다. 이 책은 앞으로 FC처럼 TS 컴파일 때만 필요한 타입은 항상 import type 구문으로 구현한다.

 

이제 <Person person={person} /> 형태의 코드가 가능하도록 Person 컴포넌트에 person 속성을 다음처럼 만들겠다.

import React from 'react'
import type {FC} from 'react
import * as D from '../data'

export type PersonProps = {
	person: D.IPerson
}
const Person: FC<PersonProps>

const Person: FC<PersonProps> = ({person}) => {
	return <Text>{JSON.stringify(person, null, 2)}</Text>
}

 

화면에 렌더링 되는 데이터의 양이 많아지면 스크를 기능이 필요하다. 리엑트 네이티브는 다음처럼 ScrollView 코어 컴포넌트를 제공하는데, Person 컴포넌트를 이 ScrollView의 자식 컴포넌트로 만들면 ScrollVIew가 제공하는 스크롤 기능을 이용해 모든 데이터를 볼 수 있다.

02-4 컴포넌트의 이벤트 속성 이해하기

onPress

on으로 시작하는 이벤트 속성에는 항상 콜백 함수를 설정해야 한다. 이를 이벤트 콜백 함수 또는 이벤트 처리기라고 한다.

리액트 네이티브에는 다음처럼 Button 코어 컴포넌트를 제공하고 이 컴포넌트는 onPress 속성을 제공한다. 

 

Alert API

리액트 네이티브는 다음과 같이 Alert API를 제공한다.

static alert(타이틀, 메시지)

Alert는 다음과 같은 alert 정적 메서드를 제공하는데, 이 메서드를 호출하면 대화상자가 화면에 나타난다.

 

Touchable Core Component

Button의 디자인 확장성이 떨어지기 때문에 대체적으로 접두어 Touchable이 붙는 다음 두 가지 코어 컴포넌트를 제공한다.

TouchableOpacity, TouchableHighlight

이 두 컴포넌트의 특징은 다음 2가지로 요악할 수 있다.

  1. 컴포넌트 영역에 터치가 일어나면 onPress 이벤트 속성에 설정된 이벤트 핸들러 콜백 함수를 호출한다.
  2. 단 한 개의 자식 컴포넌트만 올 수 있다.

두 컴포넌트는 터치가 일어났을 때 화면의 시각 효과만 다를 뿐 동작은 같다. 두 컴포넌트의 사용법은 다음과 같다.

import {TouchalbeOpacity, TouchableHighlight, Text} from 'react-native'

const onPress = () => { ... }

export default function App() {
	return(
    	<SafeAreaView>
        	<TouchalbeOpacity>
	            <Text/>
        	</TouchalbeOpacity>
            <TouchableHighlight>
	            <Text/>
            </TouchableHighlight>
        </SafeAreaView>
    )
}

사실 Text 컴포넌트도 onPress 이벤트 속성을 제공한다. 하지만 터치했을 때 시각적 효과는 없다.

 

TextInput 코어 컴포넌트

텍스트를 입력하고자 할 때는 다음처럼 TextInput 코어 컴포넌트를 사용한다.

  1. defaultValue 속성에 초깃값을 설정할 수 있다.
  2. 입력된 텍스트는 value 속성값으로 받아올 수 있다.
  3. 텍스트가 입력될 때 onChangeText 이벤트 처리기를 실행한다.
  4. placeholder 속성을 사용하여 어떤 값을 설정해야 하는지 문자열로 출력할 수 있다.
  5. editable 속성값에 false를 설정하면 입력을 못하게 할 수 있다.
  6. keyboardType 속성에 default, numeric, email-address 등의 값을 설정할 수 있다.
  7. 포커스를 가지게 하는 focus 메서드와 포커스를 잃게 하는 blur 메서드가 있다
  8. 텍스트를 입력할 수 있는 상태가 되면 onFocus 이벤트를 호출하고 텍스트를 입력할 수 없는 상태(포커스를 잃은 상태)가 되면 onBlur 이벤트를 호출한다.
  9. 자식 요소를 가질 수 없다.

onChangeText 속송에 설정할 수 있는 콜백 함수는 다음과 같은 함수 시그니처를 가진다.

onChangeText(text: string) => void

 

함수 시그니처

타입스크립트 언어에서 모든 변수는 어떤 타입을 가진다. 그리고 함수도 어떤 타입을 가진다. 여기서 함수 선언문에서 함수 이름만 제외한 부분을 함수 타입 즉 함수 시그니처라고 한다.

이벤트핸들러 속성은아무런 매개변수 없는 콜백 함수를 설정한다.