[React Native] 리액트 기본 사항

react native는 javascript로 사용자 인터페이스를 구축하는 인기 있는 오픈 소스 라이브러리인 react에서 실행됩니다. react native를 최대한 활용하려면 react 자체를 이해해야 됩니다.

react의 핵심 개념을 설명하겠습니다.

  • 컴포넌트
  • JSX
  • props
  • state

컴포넌트

고양이를 사용하여 Cat 컴포넌틀 정의해 보겠습니다.

우선 react와 react-native의 text core component를 javscript의 import를 사용하여 가져옵니다.

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

컴포넌트는 함수로 시작합니다.

const Cat = () => {}

컴포넌트를 청사진으로 생각할 수 있습니다. 함수 컴포넌트가 반환하는 것은 React 요소로 렌더링됩니다. React 요소는 화면에 무엇을 표시할지 설명할 수 있게 해줍니다.

여기서 Cat 컴포넌트는 <Text> 요소를 렌더링할 것입니다.

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

이렇게 정의된 함수 컴포넌트를 javascript의 export default를 사용하여 앱 전체에서 사용할 수 있도록 내보낼 수 있습니다.

export default Cat

return 문에는 요소를 편리하게 작성할 수 있게 해주는 javascript JSX를 사용하고 있습니다.

JSX

react와 react native는 JSX를 사용합니다. JSX는 javascript 안에서 요소를 작성할 수 있는 구문입니다. 

<Text>Hello, I am your cat!</Text>

JSX는 javascript이기 때문에 변수도 사용할 수 있습니다. 여기서 고양이의 이름을 선언하고, 중괄호를 사용하여 <Text>안에 삽입할 수 있습니다.

const Cat = () => {
 const name = 'Lami'
 return <Text>Hello, I am {name}!</Text>
}

javascript 표현식도 중괄호 안에서 동작합니다. 함수 호출도 동작합니다.

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

const getCatName = (firstName: string, lastName:string) => {
 return firstName + lastName;
}

const Cat = () => {
 return <Text>Hello, I am {getCatName('do','lami')}</Text>
}

export default Cat

JSX는 react 라이브러리에 포함되어 있기 때문에 파일 상단에 import React from 'react'가 없으면 동작하지 않습니다.

커스텀 컴포넌트

react는 react native의 core 컴포넌트를 서로 중첩하여 새로운 컴포넌트를 만들 수 있게 해줍니다. 이러한 중첩 가능하고 재사용 가능한 컴포넌트가 react 패러다임의 핵심입니다.

예를들면 <View> 안에 <Text>와 <TextInput>을 중첩할 수 있으며 react native는 이를 함께 렌더링합니다.

import React from 'react'
import {Text, TextInput, View} from 'react-native'

const Cat = () => {
 return (
  <View>
   <Text>Hello, I am...</Text>
   <TextInput
    style={{
     height: 40,
     borderColor: 'gray'
     borderWidth: 1
    }}
    defaultValue="Name me"
   />
  </View>
 )
}

export default Cat

웹 개발에 익숙하다면 <View>와 <Text>가 HTML을 떠올리게 할 수 있습니다. 이들은 애플리케이션 개발의 <div>와 <p> 태그로 생각할 수 있습니다.

이 컴포넌트를 여러 번, 여러 장소에서 코드 중복 없이 <Cat>을 사용하여 렌더링할 수 있습니다.

import React from 'react'
import <Text, View} from 'react-native'
import Cat from './Cat'

const Cafe = () => {
 return (
  <View>
   <Text>Welcome!</Text>
   <Cat />
   <Cat />
   <Cat />
  </View>
 )
}

export default Cafe

어떤 컴포넌트가 다른 컴포넌트를 렌더링하면 이를 부모 컴포넌트라고 합니다. 여기서 Cafe는 부모 컴포넌트이고, 각 Cat은 자식 컴포넌트입니다.

카페에 원하는 만큼 고양이 컴포넌트를 넣을 수 있습니다. 각 <Cat>은 고유한 요소를 렌더링하며, props로 커스터마이즈할 수 있습니다.

Props

Props는 속성의 약자입니다 .props는 react 컴포넌트를 커스터마이즈할 수 있게 해줍니다. 예를 들어 각 <Cat>에 다른 이름을 전달하여 Cat이 이를 렌더링하도록 할 수 있습니다.

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

type CatProps = {
 name: String
}

const Cat = (props: CatProps) => {
 return (
  <View>
   <Text Hello, I am {props.name}</Text>
  </View>
 )
}

const Cafe = () => {
 return (
  <View>
   <Cat name="one" />
   <Cat name="two" />
   <Cat name="three" />
  </View>
 )
}

대부분의 react native core 컴포넌트도 props로 커스터마이즈할 수 있습니다. 예를 들어, Image를 사용할 때 표시할 이미지를 정의하는 source라는 prop을 전달합니다.

<Image source={{uri:'https://example.com'}} style={{width:1,height:1}} />

Image에는 스타일과 같은 여러 props가 있으며, 이는 디자인 및 레이아웃 관련 속성-값 쌍의 JS 객체를 받아들입니다.

중괄호는 {}는 JS 객체를 전달할 때 필요합니다. {width:1, height:1} 따라서 JSX에서 JS 객체를 전달하려면 객체를 추가 중괄호로 감싸야합니다.{{width:1, height:1}}

props와 component를 이용하여 많은 것을 구축할 수 있지만 상호작용적인 것을 만들려면 state가 필요합니다.

State

props를 컴포넌트가 렌더링할 때 설정하는 인수로 생각할 수 있다면, state는 컴포넌트의 개인 데이터 저장소와 같습니다. state는 시간이 지남에 따라 변경되는 데이터나 사용자 상호작용에서 오는 데이터를 처리하는 데 유용합니다. state는 컴포넌트에 메모리를 제공합니다.

일반적인 규칙으로 렌더링 시 컴포넌트를 구성하기 위해 props를 사용합니다. 시간이 지남에 따라 변경될 것으로 예상되는 데이터는 state로 관리합니다.

다음 예시는 배고픈 고양이에게 음식을 주면 배고픔 상태에서 배부름 상태로 업데이트됩니다. 배고픔 상태를 state로 저장하여 음식주는 버튼을 누르면 배고픔 상태를 state로 업데이트합니다. 컴포넌트에 state를 추가하려면 react의 useState hook을 호출합니다. hook은 react 기능에 연결할 수 있게 해주는 함수입니다. useState는 함수형 컴포넌트에 state를 추가할 수 있게 해주는 hook입니다.

먼저 useState를 react에서 가져옵니다.

import React, {useState} frfom 'react'

그런 다음 컴포넌트 함수 내에서 useState를 호출하여 컴포넌트의 state를 선언합니다.

const Cat = () => {
 const [isHungry, setIsHungry] = useState(true)
}

useSate를 사용하여 문자열, 숫자, 부울, 배열, 객체 등 모든 종류의 데이터를 추적할 수 있습니다. 예를 들어 고양이 쓰다듬은 횟수를 추적하려면 const [timesPetted, setTimesPetted] = useState(0)을 사용할 수 있습니다.

useState를 호출하면 두 가지 일을 합니다.

1. 초기값으로 state 변수를 생성합니다. 이 경우 state 변수는 isHungry이고 초기 값은 true입니다.

2. 그 state 변수의 값을 설정하는 함수를 생성합니다. setIsHungry

사용할 이름은 상관없습니다. 그러나 패턴을 [<getter>,<setter>] = useState(<initialvalue>)로 생각하면 편리합니다.

다음으로 Button Core Component를 추가하고 onPress prop을 제공합니다.

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

이제 누군가 버튼을 누르면 onPress가 실행되어 setIsHungry(false)가 호출됩니다. state 변수 isHungry를 false로 설정합니다. isHungry가 false일 때 Button의 disabled prop은 true로 설정되고 제목도 변경됩니다.

<Button
 
 disabled={!isHungry}
 title={isHungry ? '음식주기': '고마워'}
/>

isHungry가 const임에도 불구하고 재할당되는 것처럼 보일 수 있습니다. 실제로는 state 설정 함수가 호출되면 컴포넌트가 다시 렌더링됩니다. Cat 함수가 다시 실행되고 이번에는 useState가 isHungry의 다음 값을 제공합니다.

마지막으로 고양이들을 Cafe 컴포넌트 안에 넣습니다.

const Cafe = () => {
 return (
  <>
   <Cat />
   <Cat />
  </>
 )
}

위의 <></>는 프래그먼트입니다. 인접한 JSX 요소는 인클로징 태그로 감싸야 합니다. 프래그먼트는 View와 같은 추가의 불필요한 래핑 요소 없이 이를 가능하게 합니다.