React Native2편

개발 환경 — Expo로 첫 화면 띄우기

React Native를 시작하는 가장 빠른 길인 Expo로 프로젝트를 만들고, 내 손안의 실제 기기에 첫 화면을 띄웁니다. Expo와 bare 워크플로는 무엇이 다르고, 왜 지금은 Expo가 기본 권장인지도 함께 짚습니다.

지난 편에서 React Native가 무엇인지 정리했습니다. React의 사고방식은 그대로 두고 렌더러만 네이티브로 갈아 끼운 것이라고 했죠. 이제 실제로 손을 움직일 차례입니다. 오늘의 목표는 하나입니다. 내 휴대폰 화면에 내가 만든 앱을 띄우는 것.

웹에서는 이 단계가 아주 가벼웠습니다. HTML 파일 하나를 브라우저로 열면 끝이었으니까요. 모바일은 사정이 다릅니다. 앱은 브라우저가 아니라 OS 위에서 돌아가고, 그 OS는 내 컴퓨터가 아니라 다른 기기에 있습니다. 그래서 “만든 것을 어떻게 저 기기에서 실행시킬 것인가”가 처음부터 문제가 됩니다. 이 문제를 가장 매끄럽게 풀어주는 것이 Expo입니다.


Expo가 대신 해주는 일

React Native 프로젝트를 만드는 길은 크게 두 갈래입니다.

하나는 bare(순정) 워크플로입니다. iOS 프로젝트와 Android 프로젝트를 직접 손에 쥐고 시작합니다. 그러려면 Mac에 Xcode를, 그리고 Android Studio와 JDK를 설치하고 시뮬레이터·에뮬레이터를 세팅해야 합니다. 네이티브 빌드가 실패하면 Gradle이나 CocoaPods 같은, 우리가 배우려던 것과 아무 상관 없는 도구의 오류 메시지와 씨름하게 됩니다. 많은 사람이 첫 화면도 못 보고 여기서 그만둡니다.

다른 하나가 Expo입니다. Expo는 이 네이티브 층을 대신 관리해줍니다. 우리가 자바스크립트만 쓰면, 실행에 필요한 네이티브 껍데기는 Expo가 준비된 형태로 제공합니다. 덕분에 Xcode나 Android Studio 없이도 개발을 시작할 수 있고, iPhone이 없어도 Android에서, Mac이 없어도 앱을 만들 수 있습니다. 지금은 React Native 공식 문서도 새로 시작하는 사람에게 Expo를 기본으로 권합니다.

“그럼 나중에 네이티브를 깊게 건드려야 하면 어떡하나”라는 걱정이 자연스럽게 따라옵니다. 예전에는 이 지점에서 Expo를 버리고 나가는(eject) 큰 결단이 필요했지만, 지금은 그렇지 않습니다. 필요해지면 네이티브 코드를 열어 함께 쓸 수 있는 길이 열려 있습니다. 시작할 때 미래를 저당 잡히는 선택이 아니라는 뜻입니다. 그러니 처음에는 고민 없이 Expo로 시작하는 편이 낫습니다.


프로젝트 만들기

Node.js가 설치되어 있다면 준비는 끝났습니다. 터미널에서 이 한 줄이면 프로젝트가 생깁니다.

npx create-expo-app@latest my-app
cd my-app

npx는 패키지를 전역 설치하지 않고 그때그때 내려받아 실행합니다. 웹에서 create-vitecreate-next-app을 쓰던 것과 같은 감각입니다.

만들어진 폴더를 열어보면 낯익은 것들이 보입니다. package.json이 있고, node_modules가 있고, 자바스크립트 파일들이 있습니다. 지난 편에서 말한 “React 생태계는 그대로 쓴다”는 이야기가 여기서 확인됩니다. 눈에 띄게 다른 것은 app/ 폴더인데, 이 안의 파일 구조가 곧 앱의 화면 구조가 됩니다. 웹의 파일 기반 라우팅과 비슷한 방식이고, 화면 이동 이야기는 6편에서 제대로 다루겠습니다.


실제 기기에 띄우기

이제 개발 서버를 켭니다.

npx expo start

터미널에 QR 코드가 하나 뜹니다. 여기서부터가 웹과 완전히 다른 부분입니다. 휴대폰에 Expo Go 앱을 설치하고, 그 QR 코드를 찍으세요. 잠시 뒤 방금 만든 앱이 손안의 기기에서 실행됩니다. Xcode도, 에뮬레이터도, 케이블도 필요 없습니다.

이게 가능한 이유를 알아두면 이후에 문제가 생겼을 때 당황하지 않습니다. Expo Go는 네이티브 껍데기가 미리 완성되어 있는 앱입니다. 개발 서버는 우리가 쓴 자바스크립트만 묶어서 내보내고, Expo Go가 그것을 받아 자기 안에서 실행합니다. 즉 우리는 앱을 빌드해 설치한 게 아니라, 이미 설치된 껍데기에 내 자바스크립트를 실어 보낸 것입니다. 컴퓨터와 휴대폰이 같은 와이파이에 있어야 하는 이유도 여기 있습니다. QR을 찍었는데 연결이 안 된다면 십중팔구 네트워크가 갈라져 있는 것입니다.

시뮬레이터·에뮬레이터를 쓰고 싶다면 터미널에서 i(iOS)나 a(Android)를 누르면 됩니다. 이 경우엔 Xcode나 Android Studio가 필요합니다. 웹으로 확인하고 싶다면 w를 누르면 브라우저에서도 열립니다. 다만 웹에서 잘 보인다고 안심하면 안 됩니다. 우리가 만드는 것은 결국 네이티브 화면이고, 그 진짜 모습은 기기에서 확인해야 합니다.


첫 화면 고쳐보기

app/index.tsx(혹은 .jsx)를 열고 내용을 지운 뒤 이렇게 바꿔봅시다.

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

export default function Home() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>안녕하세요, React Native.</Text>
    </View>
  );
}

저장하는 순간 휴대폰 화면이 바뀝니다. 웹에서 익숙한 그 빠른 새로고침(Fast Refresh)이 그대로 작동합니다. 코드를 고치고 저장하면 즉시 반영되고, 그 과정에서 컴포넌트의 State는 최대한 유지됩니다. 이 짧은 왕복이 React Native로 개발하는 즐거움의 큰 부분입니다.

이 짧은 코드에 지난 편에서 예고한 것들이 이미 다 들어 있습니다. div가 아니라 View를 썼고, 글자를 그냥 두지 않고 Text로 감쌌습니다. 스타일은 CSS 파일이 아니라 자바스크립트 객체로 넘겼고, flex: 1은 “남은 공간을 다 차지하라”는 뜻입니다. 각각이 3편과 4편의 주제입니다. 지금은 “아, 이렇게 생겼구나” 정도로 눈에 익혀두면 충분합니다.


자주 막히는 곳

QR을 찍었는데 앱이 안 뜬다. 대부분 네트워크 문제입니다. 컴퓨터와 휴대폰이 같은 와이파이에 있는지 보세요. 회사나 카페의 공용 와이파이는 기기 간 통신을 막아두는 경우가 있는데, 이럴 때는 npx expo start --tunnel로 우회할 수 있습니다.

저장했는데 화면이 안 바뀐다. 터미널에서 r을 눌러 새로고침해보세요. 그래도 안 되면 개발 서버를 껐다 켜는 편이 빠릅니다.

웹에서는 되는데 기기에서 깨진다. 정상입니다. 웹 미리보기는 편의 기능일 뿐이고, 두 환경은 렌더링 방식이 다릅니다. 기기에서 본 것이 진짜입니다.


정리하며

오늘 한 일은 단순하지만 중요합니다. 자바스크립트를 고치면 손안의 기기에 즉시 반영되는 왕복 고리를 만들었습니다. 앞으로의 모든 편은 이 고리 위에서 진행됩니다. 무언가를 배우면 바로 화면에서 확인할 수 있다는 뜻입니다.

다음 편에서는 방금 슬쩍 등장한 ViewText를 제대로 다룹니다. divspan도 없는 세계에서 화면은 무엇으로 만들어지는지, 그리고 왜 글자를 반드시 Text로 감싸야 하는지를 살펴보겠습니다.