Skip to main content
Version: Next

리액트 기초

React Native는 JavaScript로 사용자 인터페이스를 구축하기 위한 인기 있는 오픈소스 라이브러리인 React 위에서 동작한다. React Native를 최대한 활용하려면 React 자체를 이해하는 것이 도움이 된다. 이 섹션은 React를 처음 시작하거나 복습할 수 있는 기회를 제공한다.

React의 핵심 개념을 다룰 것이다:

  • 컴포넌트
  • JSX
  • props
  • state

더 깊이 알고 싶다면 React 공식 문서를 확인하는 것을 추천한다.

첫 번째 컴포넌트 만들기

이 React 입문서의 나머지 부분에서는 예제로 고양이를 사용한다. 이름이 필요하고 카페에서 일하는 친근하고 다가가기 쉬운 생물이다. 다음은 여러분이 만들 첫 번째 Cat 컴포넌트다:

이렇게 만든다: Cat 컴포넌트를 정의하려면 먼저 JavaScript의 import를 사용해 React와 React Native의 Text 코어 컴포넌트를 가져온다:

tsx
import React from 'react';
import {Text} from 'react-native';

컴포넌트는 함수로 시작한다:

tsx
const Cat = () => {};

컴포넌트를 청사진으로 생각할 수 있다. 함수 컴포넌트가 반환하는 것은 React 엘리먼트로 렌더링된다. React 엘리먼트는 화면에 표시하고 싶은 내용을 설명한다.

여기서 Cat 컴포넌트는 <Text> 엘리먼트를 렌더링한다:

tsx
const Cat = () => {
return <Text>Hello, I am your cat!</Text>;
};

JavaScript의 export default를 사용해 함수 컴포넌트를 앱 전체에서 사용할 수 있도록 내보낼 수 있다:

tsx
const Cat = () => {
return <Text>Hello, I am your cat!</Text>;
};

export default Cat;

이는 컴포넌트를 내보내는 여러 방법 중 하나다. 이런 종류의 내보내기는 Snack Player와 잘 작동한다. 하지만 앱의 파일 구조에 따라 다른 규칙을 사용해야 할 수도 있다. 이 JavaScript import와 export에 대한 유용한 치트시트가 도움이 될 것이다.

이제 return 문을 자세히 살펴보자. <Text>Hello, I am your cat!</Text>는 엘리먼트를 편리하게 작성할 수 있게 해주는 JavaScript 문법인 JSX를 사용한다.

JSX

React와 React Native는 JSX라는 문법을 사용한다. JSX는 자바스크립트 안에 엘리먼트를 작성할 수 있게 해주며, 예를 들어 <Text>Hello, I am your cat!</Text>와 같이 표현할 수 있다. React 문서에는 JSX에 대한 포괄적인 가이드가 있으므로 더 많은 정보를 얻을 수 있다. JSX는 자바스크립트이기 때문에 변수를 내부에 사용할 수 있다. 여기서는 고양이의 이름을 name으로 선언하고, 중괄호를 사용해 <Text> 안에 삽입한다.

중괄호 사이에는 어떤 자바스크립트 표현식도 사용할 수 있다. 예를 들어 {getFullName("Rum", "Tum", "Tugger")}와 같은 함수 호출도 가능하다.

중괄호는 JSX 안에서 자바스크립트 기능을 사용할 수 있는 포털을 만든다고 생각하면 된다!

JSX는 React 라이브러리에 포함되어 있으므로, 파일 상단에 import React from 'react'를 추가하지 않으면 작동하지 않는다!

커스텀 컴포넌트

이전에 React Native의 코어 컴포넌트를 살펴보았다. React는 이러한 컴포넌트를 서로 중첩하여 새로운 컴포넌트를 만들 수 있게 한다. 이렇게 중첩 가능하고 재사용할 수 있는 컴포넌트가 React 패러다임의 핵심이다.

예를 들어, 아래와 같이 TextTextInputView 안에 중첩하면, React Native는 이를 함께 렌더링한다:

개발자 노트

웹 개발에 익숙하다면, <View><Text>가 HTML의 <div><p> 태그를 떠올리게 할 것이다. 이들은 애플리케이션 개발에서 <div><p> 태그와 유사한 역할을 한다고 생각하면 된다.

<Cat> 컴포넌트를 여러 번, 여러 곳에서 렌더링할 수 있으며, 이를 통해 코드를 반복하지 않고도 동일한 컴포넌트를 재사용할 수 있다:

다른 컴포넌트를 렌더링하는 컴포넌트를 부모 컴포넌트라고 한다. 여기서 Cafe는 부모 컴포넌트이고, 각 Cat자식 컴포넌트이다.

카페에 원하는 만큼 고양이를 넣을 수 있다. 각 <Cat>은 고유한 엘리먼트를 렌더링하며, props를 통해 이를 커스터마이징할 수 있다.

Props

Props는 'properties'의 줄임말이다. Props를 사용하면 React 컴포넌트를 커스터마이징할 수 있다. 예를 들어, 아래 코드에서 각 <Cat> 컴포넌트에 다른 name을 전달해 Cat이 렌더링하도록 한다:

React Native의 코어 컴포넌트 대부분도 props를 통해 커스터마이징할 수 있다. 예를 들어, Image를 사용할 때 source라는 prop을 전달해 어떤 이미지를 표시할지 정의한다:

Imagestyle을 포함해 다양한 props를 지원한다. style은 디자인과 레이아웃 관련 속성-값 쌍으로 구성된 JS 객체를 받는다.

style의 너비와 높이를 감싸는 이중 중괄호 {{ }}를 주목하라. JSX에서 JavaScript 값은 {}로 참조한다. 문자열이 아닌 배열이나 숫자 같은 값을 props로 전달할 때 유용하다: <Cat food={["fish", "kibble"]} age={2} />. 하지만 JS 객체도 중괄호로 표시한다: {width: 200, height: 200}. 따라서 JSX에서 JS 객체를 전달하려면 객체를 또 다른 중괄호로 감싸야 한다: {{width: 200, height: 200}}

Text, Image, View 같은 코어 컴포넌트와 props를 활용해 다양한 것을 만들 수 있다! 하지만 인터랙티브한 기능을 구현하려면 상태(state)가 필요하다.

상태

props를 컴포넌트 렌더링을 설정하는 인자로 생각한다면, 상태는 컴포넌트의 개인 데이터 저장소와 같다. 상태는 시간이 지남에 따라 변하거나 사용자 상호작용에서 오는 데이터를 다루는 데 유용하다. 상태는 컴포넌트에 기억력을 부여한다!

일반적으로, 컴포넌트가 렌더링될 때 설정하는 데는 props를 사용하고, 시간이 지남에 따라 변할 것으로 예상되는 데이터를 추적하는 데는 상태를 사용한다.

다음 예제는 두 배고픈 고양이가 먹이를 기다리는 고양이 카페를 배경으로 한다. 고양이의 이름과 달리 시간이 지남에 따라 변할 것으로 예상되는 배고픔은 상태로 저장된다. 고양이에게 먹이를 주려면 버튼을 누르면 되는데, 이 버튼은 상태를 업데이트한다.

React의 useState Hook을 호출해 컴포넌트에 상태를 추가할 수 있다. Hook은 React 기능에 "연결"할 수 있게 해주는 함수다. 예를 들어, useState는 함수 컴포넌트에 상태를 추가할 수 있게 해주는 Hook이다. React 문서에서 다른 종류의 Hook에 대해 더 알아볼 수 있다.

먼저 React에서 useState를 다음과 같이 가져온다:

tsx
import React, {useState} from 'react';

그런 다음 컴포넌트 함수 내에서 useState를 호출해 상태를 선언한다. 이 예제에서 useStateisHungry 상태 변수를 생성한다:

tsx
const Cat = (props: CatProps) => {
const [isHungry, setIsHungry] = useState(true);
// ...
};

useState를 사용해 문자열, 숫자, 불리언, 배열, 객체 등 모든 종류의 데이터를 추적할 수 있다. 예를 들어, 고양이가 쓰다듬어진 횟수를 추적하려면 const [timesPetted, setTimesPetted] = useState(0)을 사용할 수 있다!

useState를 호출하면 두 가지 일이 일어난다:

  • 초기값을 가진 "상태 변수"를 생성한다. 이 경우 상태 변수는 isHungry이고 초기값은 true다.
  • 그 상태 변수의 값을 설정하는 함수를 생성한다. 이 경우 setIsHungry다.

이름은 중요하지 않다. 하지만 [<getter>, <setter>] = useState(<initialValue>) 패턴으로 생각하면 편리하다.

다음으로 Button Core Component를 추가하고 onPress prop을 설정한다:

tsx
<Button
onPress={() => {
setIsHungry(false);
}}
//..
/>

이제 누군가 버튼을 누르면 onPress가 실행되어 setIsHungry(false)를 호출한다. 이는 isHungry 상태 변수를 false로 설정한다. isHungryfalse가 되면 Buttondisabled prop이 true로 설정되고 title도 변경된다:

tsx
<Button
//..
disabled={!isHungry}
title={isHungry ? 'Give me some food, please!' : 'Thank you!'}
/>

isHungryconst임에도 불구하고 재할당되는 것처럼 보일 수 있다! 사실은 setIsHungry 같은 상태 설정 함수가 호출되면 해당 컴포넌트가 리렌더링된다. 이 경우 Cat 함수가 다시 실행되고, 이번에는 useStateisHungry의 다음 값을 제공한다.

마지막으로 고양이들을 Cafe 컴포넌트 안에 넣는다:

tsx
const Cafe = () => {
return (
<>
<Cat name="Munkustrap" />
<Cat name="Spot" />
</>
);
};

위의 <></>를 보았는가? 이 JSX 조각은 프래그먼트다. 인접한 JSX 엘리먼트는 반드시 감싸는 태그 안에 있어야 한다. 프래그먼트를 사용하면 View 같은 불필요한 감싸는 엘리먼트를 중첩하지 않고도 이를 수행할 수 있다.


이제 React와 React Native의 Core Components를 모두 다뤘으니, TextInput 처리를 살펴보며 이 Core Components에 대해 더 깊이 알아보자.