- React Native 공식 문서의 Tutorial(Learn the Basics)을 번역한 글입니다. 2020년 7월 30일 현재 React Native 0.63 버전을 기준으로 작성되었습니다.
- Translated by Do Junggeun (도정근)
리액트 네이티브는 리액트와 유사하지만 웹 컴포넌트(web components) 대신 네이티브 컴포넌트(native components)를 다룹니다. 따라서 리액트 네이티브 앱의 기본 구조를 이해하기 위해서는 JSX, components, states
와 props
같은 리액트의 기본 개념을 이해하고 있어야 합니다. 이미 리액트를 알고 있더라도 native components 등 리액트 네이티브의 특징적인 개념을 배워야 합니다. 이 튜토리얼은 리액트를 경험해본 사람과 그렇지 않은 사람 모두를 대상으로 합니다.
이제 시작해봅시다.
우리는 우리 분야의 전통에 따라 먼저 "Hello, world!"를 출력하는 기능만을 가지는 앱을 만들어야 합니다. 다음과 같이 말이죠:
import React from 'react'; import { Text, View } from 'react-native'; const HelloWorldApp = () => { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text>Hello, world!</Text> </View> ) } export default HelloWorldApp;
결과가 궁금하다면 웹 시뮬레이터에서 샘플 코드를 직접 가지고 놀 수 있습니다. 또한 App.js 파일에 코드를 붙여넣어 당신의 기기(local machine)에 실제 앱을 만들어볼 수도 있습니다.
그 후에는 함수형 컴포넌트(Functional Components)이면서 웹에서의 React와 같은 방식으로 동작하는 HelloWorldApp
함수가 등장합니다. 이 함수는 View
컴포넌트를 리턴하며, View
컴포넌트는 Text
컴포넌트를 자식으로 갖고있고 style도 적용되어 있습니다.
Text
컴포넌트는 텍스트를 렌더링하고, View
컴포넌트는 컨테이너(container)를 렌더링합니다. 이 컨테이너는 여러 style들이 적용되어 있는데, 각각이 어떤 기능을 하는지 알아봅시다.
첫번째 style은 flex:1
인데, flex prop은 각각의 요소들이 세로 축을 따라 사용 가능한 공간에 어떻게 "채워지는"지를 정의합니다.
다음 style은 justifyContent: "center" 입니다. 이는 컨테이너의 자식 컴포넌트들을 컨테이너의 세로 축 중앙에 정렬시킵니다. 마지막으로 alignItems: "center" 는 컨테이너의 자식 컴포넌트들을 컨테이너의 가로 축 중앙에 정렬시킵니다.
이들 중 일부는 JavaScript가 아닌 것처럼 보일 텐데, 겁먹지 마세요. 이것이 우리의 미래입니다.
ES2015(ES6)는 현재 공식 표준이 되었지만, 아직 모든 브라우저에서 지원되지 않기 때문에 웹 개발에 아직 사용되지 않는 경우가 많습니다. 하지만 React Native는 ES2015를 지원하므로 이것들을 호환성에 대한 걱정 없이 사용해도 됩니다. 위의 예시에서 import
, from
, class
및 extends
는 모두 ES2015의 기능입니다. ES2015에 익숙하지 않더라도 (이 튜토리얼의 샘플 코드 등의) 샘플 코드를 읽어보면 금방 이해할 수 있을 것입니다. 원한다면 이 페이지를 통해 ES2015의 기능을 살펴볼 수 있습니다.
이 샘플 코드에 있는 또 다른 색다른 것은 <View><Text>Hello world!</Text></View>
입니다. 이는 JSX(JavaScript에 XML을 내장하기 위한 문법)입니다. 많은 프레임워크가 마크업 언어 내에 코드를 삽입할 수 있는 전문 템플릿 언어를 사용합니다. 그런데 React는 그 반대입니다. JSX는 코드 안에 마크업 언어를 쓸 수 있게 합니다. 이것은 웹의 HTML처럼 보이지만, <div>
와 <span>
대신 React 컴포넌트를 사용합니다. 우리의 예시에서 <Text>
는 텍스트를 표시하는 코어 컴포넌트(Core Componenet)이고 View
는 <div>
나 <span>
같은 역할을 합니다.
즉, 이 코드는 HelloWorldApp
이라는 새로운 컴포넌트를 정의합니다. 리액트 네이티브 앱을 만들 때, 당신은 수 많은 새로운 컴포넌트를 만드는 것입니다. 당신이 스크린에서 볼 수 있는 모든 것은 일종의 컴포넌트입니다.
대부분의 컴포넌트는 생성될 때 각기 다른 매개변수(parameters)를 통해 커스터마이징 될 수 있습니다. 이러한 매개변수들을 props라고 합니다. 컴포넌트 역시 props
를 사용할 수 있습니다. 이렇게 하면 하나의 컴포넌트를 앱의 여러 다른 곳에서 조금씩 다른 속성(properties)을 부여하여 사용할 수 있습니다. 함수형 컴포넌트의 props.{NAME}
혹은 클래스형 컴포넌트의 this.props.{NAME}
를 사용하면 됩니다.여기에 예시가 있습니다:
import React from 'react'; import { Text, View, StyleSheet } from 'react-native'; const styles = StyleSheet.create({ center: { alignItems: 'center' } }) const Greeting = (props) => { return ( <View style={styles.center}> <Text>Hello {props.name}!</Text> </View> ); } const LotsOfGreetings = () => { return ( <View style={[styles.center, {top: 50}]}> <Greeting name='Rexxar' /> <Greeting name='Jaina' /> <Greeting name='Valeera' /> </View> ); } export default LotsOfGreetings;
name
을 prop으로 사용하면 Greeting
컴포넌트를 커스터마이징 할 수 있습니다. 따라서 우리는 각각의 인사(greeting)에 컴포넌트를 재사용할 수 있습니다. 이 예시는 또한 Greeting
컴포넌트를 JSX 문법으로 사용하고 있습니다. 이렇게 할 수 있는 힘이 리액트를 멋지게 만드는 것입니다.
이 예시에서 또 다른 새로운 것은 View 컴포넌트입니다. View는 스타일과 레이아웃을 제어하기 위해 사용되는 다른 구성요소의 컨테이너로써 유용하게 사용됩니다.
props
와 기본적인 Text, Image, View 컴포넌트로 다양한 정적 스크린을 만들 수 있습니다. 상황(시간)에 따라 변하는 앱을 만드는 방법을 배우기 위해서는 State를 먼저 배워야 합니다.
읽기 전용(read-only)이며 수정될 수 없는 props와 달리, state는 React 컴포넌트가 사용자의 행위, 네트워크 응답 등에 대응하여 시간에 따라 출력 결과를 변경할 수 있도록 해줍니다.
React 컴포넌트에서 props는 부모 컴포넌트에서 자식 컴포넌트로 전달되는 변수입니다. state 역시 변수인데, state는 매개변수(parameter)로 전달되지 않고 오히려 컴포넌트가 내부적으로 초기화하고 관리한다는 차이가 있습니다.
위 이미지에서 볼 수 있듯, React와 React Native에서 state를 다루는데는 차이가 없습니다. hooks를 사용하여 클래스형 컴포넌트와 함수형 컴포넌트에서 모두 state를 사용할 수 있습니다!
아래는 클래스를 사용한 동일한 예시(read-only)입니다.
import React, { Component } from 'react' import { StyleSheet, TouchableOpacity, Text, View, } from 'react-native' class App extends Component { state = { count: 0 } onPress = () => { this.setState({ count: this.state.count + 1 }) } render() { return ( <View style={styles.container}> <TouchableOpacity style={styles.button} onPress={this.onPress} <Text>Click me</Text> </TouchableOpacity> <View> <Text> You clicked { this.state.count } times </Text> </View> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, button: { alignItems: 'center', backgroundColor: '#DDDDDD', padding: 10, marginBottom: 10 } }) export default App;