상세 컨텐츠

본문 제목

[리액트를 다루는 기술] 3장 컴포넌트

21-22/21-22 리액트 스타터 -1

by Kimpeep 2021. 11. 8. 18:46

본문

728x90

3.1 클래스형 컴포넌트

컴포넌트를 선언하는 방식은 두 가지입니다 하나는 함수형 컴포넌트이고 다른 하나는 클래스형 컴포넌트입니다.

import React, { Component } from 'react'; 
class App extends Component { 
render() { const name = 'react'; 
return <div className="react">{name}</div>; 
} } 
export default App;

클래스형 컴포넌트는 다음과 같이 이루어져 있습니다. 클래스형 컴포넌트이지만 역할을 이전에 보았던 함수형 컴포넌트와 같습니다. 하지만 클래스형 컴포넌트의 경우 state 기능 및 라이프사이클 기능을 사용할 수 있다는 것과 메서드를 정의할 수 있다는 점에서 함수형 컴포넌트와 차이점이 있습니다. 클래스형 컴포넌트에서는 render 함수가 꼭 있어야 하고 그 안에서 보여 주어여 할 JSX를 반환해야 합니다. 리애트 공식 매뉴얼에서는 컴포넌트를 새로 작성할 떼 함수형 컴포넌트와 Hooks를 사용하도록 권장하고 있습니다. 하지만 그렇다해서 클래스형 컴포넌트가 사라지는 것은 아니므로 클래스형 컴포넌트의 기능도 꼭 알아 두어야 합니다.

3.2 첫 컴포넌트 생성

3.2.1 src 디렉터리에 MyComponent.js 파일 생성하기

 

3.2.2 코드 작성하기

import React from 'react'; 
const MyComponent = () => { return <div>나의 새롭고 멋진 컴포넌트</div>; }; 
export default MyComponent;

함수형 컴포넌트로 코드를 작성해보았습니다. 함수를 작성할 때 function 키워드 대신에 () => {}를 사용하여 함수를 만들어 주었는데, 이것는 화살표 함수입니다. 화살표 함수(arrow function)는 ES6 문법에서 함수를 표현하는 새로운 방식입니다. 이 문법은 주로 함수를 파라미터로 전달할 때 유용합니다. 일반 함수는 자신이 종속된 객체를 this로 가리키며, 화살표 함수는 자신이 종속된 인스턴스를 가리킵니다.

function twice(value) { return value * 2; } const triple = (value) => value * 3;

화살표 함수는 값을 연산하여 바로 반환해야 할 때 사용하면 가독성을 높일 수 있습니다. 위의 예시처럼 따로 { }를 열어 주지 않으면 연산한 값을 그대로 반환합니다. 함수형 컴포넌트 사용 시 function키워드를 사용하는 것과 화살표 문법을 사용하는 것 과는 큰 차이는 없습니다.

 

3.2.3 모듈 내보내기 및 불러오기

  • 모듈 내보내기(export)
export default MyComponent;

이 코드는 다른 파일에서 이 파일을 import 할 때, 위에서 선언한 MyComponent 클래스를 불러오도록 설정합니다.

  • 모듈 불러오기(import)
import React from "react"; 
import MyComponent from './MyComponent'; 
const App = () => { return <MyComponent />; }; 
export default App;

위 코드에서 두 번째 import 줄은 MyComponent 컴포넌트를 불러오는 역할을 합니다.

 

3.3 props

props는 컴포넌트 속성을 설정할 때 사용하는 요소입니다. props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정할 수 있습니다.

 

3.3.1 JSX 내부에서 props 렌더링

import React from 'react'; 
const MyComponent = props => { return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>; }; 
export default MyComponent;

MyComponent 컴포넌트에서 name이라는 props를 렌더링 하도록 설정해 보았습니다. props값은 컴포넌트 함수의 파라미터로 받아 와서 사용할 수 있으며, props를 렌더링 할 때는 JSX 내부에서 { } 기호로 감싸줍니다.

 

3.3.2 컴포넌트를 사용할 때 props 값 지정하기

import React from "react";
import MyComponent from './MyComponent'; 
const App = () => { return <MyComponent name="React" />; }; 
export default App;

App 컴포넌트에서 MyComponent의 props 값을 지정합니다.


3.3.3 props 기본값 설정: defaultProps

props 값을 지정할지 않았을 때 보여 줄 기본값을 설정할 수 있습니다.

MyComponent.defaultProps = { name: '기본 이름' };

MyComponent 컴포넌트에 다음 구문을 작성하면 '기본 이름'이 기본값이 됩니다.

 

3.3.4 children

children은 컴포넌트 태그 사이의 내용을 보여 주는 props입니다.

(...) const App = () => { return <MyComponent>리액트 스타터</MyComponent>; }; (...)

App 컴포넌트에서 MyComponent 태그 사이에 작성한 리액트 스타터라는 문자열을 MyComponent 내부에서 보여 주려면 MyComponent 컴포넌트에 {props.children}을 작성해야 합니다.

 

3.3.5 비구조화 할당 문법을 통해 props 내부 값 추출

ES6의 비구조화 할당 문법을 사용하여 내부 값을 바로 추출할 수 있습니다.

(...) const MyComponent = props => { const {name, children} = props;
return <div>안녕하세요, 제 이름은 {name}입니다. <br /> children 값은 {children} 입니다. </div>; }; (...)

다음과 같이 작성하면 name과 children을 더 짧은 코드로 사용할 수 있습니다. 이처럼 객체에서 값을 추출하는 문법을 비구조화 할당이라고 부릅니다. 구조 분해 문법이라고도 하며, 함수의 파라미터 부분에서도 사용할 수 있습니다.


3.3.6 propTypes를 통한 props 검증

컴포넌트의 필수 props를 지정하거나 props의 타입을 지정할 때 propTypes을 사용합니다.
propTypes를 사용하기 위해서 코드 상단에 import 구문을 통해 불러옵니다.

import React from 'react'; 
import PropTypes from 'prop-types'; 
const MyComponent = ({name, children}) => { 
return <div>안녕하세요, 제 이름은 {name}입니다. <br /> children 값은 {children} 입니다. </div>; }; MyComponent.defaultProps = { name: '기본 이름' }; MyComponent.propTypes = { name: PropTypes.string.isRequired }; export default MyComponent;

다음과 같이 작성하면 name 값은 무조건 string 형태로 전달하도록 설정됩니다. propTypes를 지정할 때 뒤에 isRequired를 붙여주면 propTypes를 지정하지 않았을 때 경고 메시지를 띄워 줍니다.


3.3.7 클래스형 컴포넌트에서 props 사용하기

import PropTypes from 'prop-types'; 
import React, {Component} from 'react'; 
class MyComponent extends Component { 
render() { const {name, children, favoriteNumber} = this.props;
return( <div>안녕하세요, 제 이름은 {name}입니다. <br /> children 값은 {children} 입니다. </div> 
); } } (..)

다음과 같이 MyComponent를 클래스형 컴포넌트로 변환해서 사용할 수도 있습니다. 클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 됩니다. defaultProps와 propTypes는 똑같은 방식으로 설정할 수 있습니다.

 

3.4 state

state는 컴포넌트 내부에서 바뀔 수 없는 값을 의미합니다. 리액트에는 두 가지 종류의 state 가 있습니다. 하나는 컴포넌트가 지니고 있는 state이고, 다른 하나는 함수형 컴포넌트에서 useState 함수를 통해 사용하는 state입니다.

3.4.1 클래스형 컴포넌트의 state

컴포넌트에 state를 설정할 때는 constructor 메서드를 작성하여 설정합니다. 이는 컴포넌트의 생성자 메서드이며, 클래스형 컴포넌트에서 constructor 작성 시에는 반드시 super(props)를 호출해 주어야 합니다. 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속하고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해 줍니다. 또한, 컴포넌트의 state는 객체 형식이어야 합니다.

 constructor(props) { super(props); this.state = { number: 0 }; }


render 함수에서 현재 state를 조회할 때는 this.state를 조회합니다. 이벤트로 설정할 함수는 화살표 문법을 사용하여 넣어줍니다. 현재는 state 값을 바꿀 수 있게 하는 this.setState라는 함수를 사용했습니다. this.setState 함수는 인자로 전달된 객체 안에 들어 있는 값만 바꿔 줍니다.

render() { const { number } = this.state; 
//state를 조회할 때는 this.state로 조회합니다. 
return ( <div> <h1>{number}</h1> <button 
//onClick을 통하여 버튼이 클릭됐을 때 호출할 함수를 지정합니다. 
onClick={() => { this.setState({ number: number + 1 }); }} > +1 </button> </div> ); }


아래와 같이 작성하면 constructor 메서드를 선언하지 않고도 state 초기값을 설정할 수 있습니다.

(...) class Counter extends Component { state = { number: 0, fixedNumber: 0 }; (...)


this.setState를 사용하여 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트됩니다. this.setState를 사용한다고 해서 state값이 바로 바뀌지는 않기 때문에, this.setState를 사용할 때 객체 대신에 함수를 인자로 넣어 줍니다. this.setState의 인자로 함수를 넣어 줄 때는 다음과 같은 형식으로 작성합니다.

this.setState((prevState, props) => { return { //업데이트하고 싶은 내용 } })

prevState는 기존 상태이고 props는 현재 지니고 있는 props입니다. 만약 업데이트 과정에서 props가 필요하지 않다면 생략해도 됩니다.

setState를 사용하여 값을 업데이트한 다음 특정 작업을 하고 싶을 때는 setState의 두 번째 파라미터로 콜백(callback) 함수를 등록하여 처리할 수 있습니다.

 this.setState( { number: number + 1 }, () => { 
 console.log('방금 setState 가 호출되었습니다.'); 
 console.log(this.state); } );

 

3.4.2 함수형 컴포넌트에서 useState 사용

리액트 16.8 버전 이후부터는 useState라는 함수를 사용하여 함수형 컴포넌트에서도 state를 사용할 수 있게 되었습니다. 이 과정에서 Hooks라는 것을 사용합니다.

  • 배열 비구조화 할당

배열 비구조화 할당은 객체의 비구조화 할당과 비슷합니다. 배열 안에 들어 있는 값을 쉽게 추출할 수 있도록 해 주는 문법입니다. 아래의 코드는 array 안에 있는 값을 one과 two에 담아주는 코드입니다.

const array = [1, 2]; const one = array[0]; const two = array[1];

이를 배열 비구조화 할당을 사용하여 표현하면 다음과 같습니다.

const array = [1, 2]; const [one, two] = array;

 

  • useState 사용하기

useState 함수의 인자에는 상태의 초기값을 넣어줍니다. 초기값의 형태는 숫자, 문자열, 객체, 배열 등 무엇이든지 상관없습니다.

import React, { useState } from 'react'; 
const Say = () => { const [message, setMessage] = useState(''); 
const onClickEnter = () => setMessage('안녕하세요!'); 
const onClickLeave = () => setMessage('안녕히 가세요!'); 
return ( <div> <button onClick={onClickEnter}>입장</button> 
<button onClick={onClickLeave}>퇴장</button> <h1>{message}</h1> </div> 
); }; export default Say;

함수를 호출하면 배열이 반환됩니다. 배열의 첫 번째 원소는 현재 상태이며, 두 번째 원소는 상태를 바꾸어 주는 세터(Setter) 함수입니다. 배열 비구조화 할당을 통해 이름을 자유롭게 정해 줄 수 있습니다. useState는 한 컴포넌트에서 여러 번 사용해도 상관없습니다.

 

3.5 state를 사용할 때 주의 사항

state 값을 바꾸어야 할 때는 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 합니다.
배열이나 객체를 업데이트해야 할 때는 배열이나 객체의 사본을 만들고 그 사본에 값을 업데이트한 후, 그 사본의 상태를 setState 또는 세터 함수를 통해 업데이트해야 합니다. 객체에 대한 사본을 만들 때는 spread 연산자라 불리는... 을 사용하여 처리하고, 배열에 대한 사본을 만들 때는 배열의 내장 함수들을 사용합니다.

 

3.6 정리

컴포넌트를 만들어서 내보내고 불러오는 방법과 propsstate를 사용하는 방법을 알아보았습니다. props와 state는 컴포넌트에서 사용하고 렌더링 할 데이터를 담고 있다는 점에서 비슷하지만 역할은 매우 다릅니다. props는 부모 컴포넌트가 설정하고 state는 컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트할 수 있습니다. 또한, state를 다루기 위해 클래스형 컴포넌트의 state함수형 컴포넌트의 useState에 대해서도 알아보았습니다. 앞으로 새로운 컴포넌트를 만들 때는 useState를 사용할 것을 권장합니다.


Quiz

1. 컴포넌트를 선언하는 방식 두 가지는?
2. 컴포넌트 속성을 설정할 때 사용하는 요소로, 부모 컴포넌트에서 설정하는 것은?
3. 객체에서 값을 추출하는 문법을 oooo oo이라고 부른다.
4. 클래스형 컴포넌트에서 state의 초기값은 어떤 형태여야 하는가?
5. 함수형 컴포넌트에서 state를 사용할 수 있게 해 주는 함수는?


Quiz 정답

더보기

1. 함수형 컴포넌트, 클래스형 컴포넌트

2. props

3. 비구조화 할당

4. 객체 형태

5. useState





Corner React Starter #1
Editor dori

728x90

관련글 더보기