다라다라V
article thumbnail
Published 2022. 10. 15. 01:22
[React] 03. 컴포넌트 프레임워크/REACT
728x90
반응형

앞선 포스트에서 컴포넌트(component)는 리액트 프로젝트에서 특정 부분이 어떻게 생길지를 결정하는 선언체라고 배웠습니다. 리액트의 컴포넌트는 함수형 컴포넌트 클래스형 컴포넌트로 두 가지로 선언될 수 있습니다.

클래스형 컴포넌트와 함수형 컴포넌트를 비교하며 컴포넌트를 생성해보겠습니다. 또한 컴포넌트에서 사용하거나 렌더링 하는 데이터를 담는 props와 state의 차이점과 선언 방식을 배우겠습니다.

📌 클래스형 컴포넌트

📚 클래스형 컴포넌트

컴포넌트를 선언하는 방식은 클래스 컴포넌트와 함수 컴포넌트로 나뉩니다. 클래스형 컴포넌트와 함수 컴포넌트는 state 기능 및 라이프 사이클 기능, 임의 메서드 정의 등에서 차이가 납니다.

각 방법으로 작성된 코드를 보면서 차이점을 비교해보자.

 

📃 클래스 컴포넌트

import {Component} from "react";

class App extends Component {
    render() {
        const name = 'react';
        return <div className='react'> {name} </div>;
    }
}

export default App;

 

📃 함수 컴포넌트

import './App.css';

function App() {
    const name = "리액트";
    return <div className='react'> {name} </div>;
}

export default App;

 

함수 컴포넌트의 특징은 다음과 같습니다.

  • 클래스 컴포넌트보다 선언하기 편리
  • 클래스 컴포넌트보다 메모리 자원을 덜 사용하고, 실제 배포할 때도 결과물의 파일 크기가 더 작습니다.
  • 리액트 v16.8 업데이트로 state와 라이프사이클 API도 사용이 가능해졌습니다.

 

리액트 v16.8 업데이트로 Hooks가 도입되었고 함수 컴포넌트도 클래스 컴포넌트와 같이 작업을 할 수 있게 되었습니다. 리액트 공식 매뉴얼에서는 함수 컴포넌트와 Hooks를 사용하도록 권장합니다. 그러나 이전의 작성된 코드들의 유지 및 보수를 위하여 클래스 컴포넌트도 반드시 알아두어야합니다.


📌 첫 컴포넌트 생성

📚 함수 컴포넌트 작성하기

 

컴포넌트는 다음의 세 단계를 거쳐서 만들 수 있습니다.

  1. 파일 만들기
  2. 코드 작성하기
  3. 모듈 내보내기 및 불러오기

VS 코드에서 파일을 만드는 방법은 src 디렉터리 - [우클릭] - <파일이름>.js 작성하면 됩니다.


📚 코드 작성하기

 

앞으로는 NewComponent.js 파일을 새로 만들어 코드 작업을 진행하도록 하겠습니다.

// NewComponent.js

const NewComponent = () => {
    return <div> 화살표 함수를 이용한 컴포넌트 </div>
};

export default NewComponent;

 

위 코드는 화살표 함수를 이용하여 만든 함수 컴포넌트입니다. JavaScript ES6 문법에서 function 키워드 외에도 화살표 함수로 함수를 선언하여 사용할 수 있습니다. 화살표 함수는 값을 연산하여 바로 반환해야할 때 사용하면 가독성을 높일 수 있습니다.


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

📃 모듈 내보내기

export default NewComponent;

 

이 코드는 다른 파일에서 이 파일을 import 할 때, 위 클래스를 불러오도록 합니다

 

📃 모듈 불러오기

// App.js

import NewComponent from "./NewComponent";

const App = () => {
  return <NewComponent />
}

export default App;

 

import 키워드를 통해 NewComponent 컴포넌트를 불러 새로 렌더링할 수 있습니다.


📌 props

📚 props 값 사용

props는 properties의 줄임말로 컴포넌트의 속성을 설정할 수 있습니다. 이 props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정할 수 있습니다.

 

📃 JSX 내부에서 props 렌더링

NewComponent.js에 다음의 내용을 작성합니다. 

// NewComponent.js

const NewComponent = props => {
    return <div> {props.prog}에서 컴포넌트를 만듭니다. </div>
};
 
export default NewComponent;
  • 해당 컴포넌트에서 program이라는 props를 렌더링하도록 하는 코드
  • props 값은 매개변수(파라미터)로 사용

 

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

NewComponent를 불러오는 부모 컴포넌트(App.js)에 다음의 내용을 작성합니다.

// App.js

import NewComponent from "./NewComponent";

const App = () => {
  return <NewComponent prog="리액트" />;
};

export default App;
  • 부모 컴포넌트에서 props의 값을 지정

📚 props 기본값 설정: defaultProps

위의 부모 컴포넌트의 prog 값을 지우면 prog 자리에 아무 내용도 출력되지 않습니다. props 값을 따로 지정하지 않았을 때 보여줄 기본값은 defaultProps로 설정할 수 있습니다. .

// NewComponent.js

const NewComponent = props => {
    return <div> {props.prog}에서 컴포넌트를 만듭니다. </div>;
};

NewComponent.defaultProps = {
    prog : "REACT"
}

export default NewComponent;

NewComponent.js 파일에 defaultProps을 이용해 기본 값을 설정해줄 수 있습니다.


📚 태그 사이의 내용을 보여주는 children

리액트에서는 컴포넌트 태그 사이의 내용을 보여주는 props도 있습니다. children이라는 값을 통해 태그 사이에 작성한 내용을 자식 컴포넌트 내부에서 보여줄 수 있습니다. 자식 노드에서는 props.children을 통해 접근할 수 있습니다. 

(코드 내의 (...) 은 새로 작성된 부분 외의 코드는 이전에 작성한 코드와 동일함을 의미합니다.)

// NewComponent.js

const NewComponent = props => {
    return (
        <div> 
            {props.prog}에서 컴포넌트를 만듭니다. <br/>
            children의 값은 {props.children}입니다.
        </div>
    );    
};
(...)
export default NewComponent;
// App.js

import NewComponent from "./NewComponent";

const App = () => {
  return <NewComponent> ~태그 사이~ </NewComponent> 
}

export default App;

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

props 값을 조회할 때마다 props.prog, props.children 같이 prog. 이라는 키워드가 필요합니다. ES6의 비구조화 할당 문법을 사용하여 내부 값을 더 편히 추출할 수 있습니다.

// NewComponent.js

const NewComponent = props => {
    const {prog, children} = props;
    return (
        <div> 
            {prog}에서 컴포넌트를 만듭니다. <br/>
            children의 값은 {children}입니다.
        </div>
    );    
};
(...)
export default NewComponent;
  • 객체에서 값을 추출하는 문법을 비구조화 할당(destructing assignment)라고 부름
  • 구조 분해 문법이라고도 불림

 

함수의 파라미터 부분에서도 사용 가능합니다. 함수의 파라미터가 객체라면 값을 바로 비구조화하여 다음과 같이 코드를 작성할 수 있습니다.

// NewComponent.js

const NewComponent = ({prog, children}) => {
    return (
        <div> 
            {prog}에서 컴포넌트를 만듭니다. <br/>
            children의 값은 {children}입니다.
        </div>
    );    
};
(...)
export default NewComponent;

📚 propTypes를 통한 props 검증

컴포넌트의 필수 props를 지정하거나 타입을 지정할 때는 propTypes를 사용합니다. propTypes를 지정하는 방법은 defaultProp을 설정하는 것과 비슷합니다. propTypes을 사용하기 위해 코드 상단에 import를 해야합니다.

import PropTypes from 'prop-types';

 

📃 타입 설정하기 

// NewComponent.js

import PropTypes from 'prop-types';

(...)

NewComponent.propTypes = {
	prog: PropTypes.string
};

export default NewComponent;

 

  • prog의 내용은 반드시 String으로 지정되어야 함
  • 잘못된 타입으로 값을 지정한 뒤 개발자 도구의 Console 탭을 열면 오류 창이 뜸

 

📃 isRequired를 사용하여 필수 propTypes 설정

propTypes을 지정할 때 경고 메세지를 발생시킬 수 있습니다. 

// NewComponent.js

import { PropTypes } from "prop-types";

const NewComponent = ({prog, children, age}) => {
    return (
        <div> 
            {prog}에서 컴포넌트를 만듭니다. <br/>
            children의 값은 {children}입니다. <br/>
            저의 나이는 {age}세 입니다.
        </div>
    );    
};

NewComponent.defaultProps = {
    prog : "리액트"
}

NewComponent.propTypes = {
    prog: PropTypes.string,
    age: PropTypes.number.isRequired
};

export default NewComponent;

 

부모 컴포넌트인 App.js에서 age의 값이 설정되지 않는 다면 콘솔창에서 오류 메시지를 보여줄 것 입니다.

// App.js

import NewComponent from "./NewComponent";

const App = () => {
  return(
    <NewComponent prog = "React" age = {100} >
      ~ children 값 ~
    </NewComponent> 
  ) 
}

export default App;

 

📃 PropTypes의 종류

https://github.com/facebook/prop-types 에서 PropTypes에 대한 내용을 볼 수 있습니다.


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

클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 됩니다. defaultProps와 propTypes는 똑같은 방식으로 설정할 수 있습니다. 클래스형 컴포넌트에서 props 값을 조회하는 코드입니다.

// NewComponent.js

import { Component } from "react";
import PropTypes from "prop-types";

class NewComponent extends Component {
    render() {
        const {prog, children, age} = this.props; //비구조화 할당
        return (
            <div>
                {prog}에서 컴포넌트를 만듭니다. <br/>
                children의 값은 {children}입니다. <br/>
                저의 나이는 {age}세 입니다.
            </div>
        )
    }
}
NewComponent.defaultProps = {
    prog : "리액트"
}

NewComponent.propTypes = {
    prog: PropTypes.string,
    age: PropTypes.number.isRequired
};

export default NewComponent;

 

defaultProps와 propTypes는 class 내부에서도 지정 가능합니다.

// NewComponent.js

import { Component } from "react";
import PropTypes from "prop-types";

class NewComponent extends Component {    
    static defaultProps = {
        prog : "리액트"
    };
    static propTypes = {
        prog: PropTypes.string,
        age: PropTypes.number.isRequired
    }
    render() {
    	( ... )
    }
}

export default NewComponent;

📌 state

📚 state

  • state 컴포넌트 내부에서 바뀔 수 있는 값을 의미
  • props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하며 자신은 해당 props를 읽기 전용으로만 사용
  • state는 컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트 할 수 있음
  • 일반 변수는 값이 변경될 때 html에 자동 변경되지 않지만, state는 값이 변경되면 html에 재랜더링 해줌
    => 값의 변화가 자주 있을 때 state를 사용
  • 클래스형 컴포넌트는 state, 함수 컴포넌트에서는 useState를 사용

📚 클래스형 컴포넌트의 state

클릭으로 숫자를 늘이는 Counter.js를 만들어 봅시다.

// Counter.js

import { Component } from "react";

class Counter extends Component {
    constructor(props) {
        super(props);

        this.state = {
            number: 0 // state 초깃값 설정하기
        };
    }
    render() {
        const {number} = this.state; // state 조회시 this.state를 조회
        return (
            <div>
                <h1> {number} </h1>
                <button
                    /* onClick 함수를 사용하여 클릭 시 숫자를 늘려주는 버튼 만들기 */
                    onClick = {() => {
                        /* this.setState를 사용하여 state에 새로운 값을 지정 */
                        this.setState( {number: number +1 } );
                    }}
                >
                    +1
                </button> 
            </div>
        );
    }
}

export default Counter;

📚 함수 컴포넌트에서 useState 사용하기

📃 배열 비구조화 할당

  • 배열 비구조화 할당 객체 비구조화 할당과 비슷함
  • 배열 안에 들어있는 값을 쉽게 추출하도록 하는 문법
  • Destructing 문법을 통해 형태를 맞추어 값을 쉽게 할당
const array = [1, 2];
const one = array[0];
const two = array[1];

위 코드는 배열 비구조화 할당을 통해 더 간단히 표현될 수 있습니다.

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

 

📃  useState 사용하기

리액트 16.8 이전 버전에서는 함수 컴포넌트에서 state를 사용할 수 없었습니다. 그러나 업데이트 이후, Hooks가 생기면서  useState 함수를 사용하여 함수 컴포넌트에서도 state를 사용할 수 있습니다. Hooks의 종류 중 하나인 useState를 먼저 배우겠습니다.

useState는 배열 비구조화 할당 문법과 같습니다. useState를 활용한 코드를 Say.js에 작성해봅시다.

// Say.js

import { 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;

 

  • useState 함수 인자에는 상태의 초깃값을 지정, 객체가 아니어도 괜찮음
  • 함수를 호출하면 배열이 반환
    *  배열의 첫 번째 원소는 현재 상태
    *  배열의 두 번째 원소는 상태를 바꾸어주는 함수,  setter 함수
// App.js

import Say from "./Say";

const App = () => {
  return <Say />
}

export default App;

📚 한 컴포넌트에서 useState 여러 번 사용하기

// Say.js

import { useState } from "react";

const Say = () => {
    const [message, setMessage] = useState('');
    const onClickEnter = () => setMessage("안녕하세요!");
    const onClickLeave = () => setMessage("안녕히가세요!");

    const [color, setColor] = useState('black');

    return (
        <div>
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1 style = {{ color }}> {message} </h1>
            <button style={{ color: 'red'}} onClick={() => setColor('red')}>
                빨간색
            </button>
            <button style={{ color: 'green'}} onClick={() => setColor('green')}>
                초록색
            </button>
            <button style={{ color: 'blue'}} onClick={() => setColor('blue')}>
                파란색
            </button>
        </div>
    );
};

export default Say;

📚 state 사용 시 주의 사항

  • state 값을 바꿀때는 setState 혹은 useState를 통해 전달받은 세터(setter) 함수를 사용
  • 배열이나 객체를 업데이트 할 때는 사본에 값을 업데이트하고 그 사본의 상태를 setState나 세터 함수로 업데이트
  • 사본은 spread 연산자를 사용하고 배열의 사본은 내장 함수를 활용

 

 

 

반응형
profile

다라다라V

@DaraDaraV

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!