01.5. React Component

React.js

01.5. Component

앞선 01.1/01.2 React JS 특징 및 설치환경 에서 설명했듯이 컴포넌트는 특정 부분이 어떻게 생길지 정하는 선언체이며, LifeCycle API를 이용하여 컴포넌트가 화면에서 나타날 때, 사라질 때, 변화가 일어날 때 주어진 작업을 처리할 수 있고, 메서드를 만들어 기능을 붙일 수도 있다.

리액트 프로젝트에서 서로 조합이 가능한, 모듈화된 컴포넌트를 사용해 만든다.

01.5.1. 컴포넌트 생성하기

01.5.1.1. 컴포넌트 초기 코드 생성

src 디렉터리 내부에 NewComponent.js 파일 생성
termianl이나 cmd에서 명령어를 이용해 만들어도 되고, VS Code 왼쪽 사이드바에 있는 파일 목록에서 마우스 오른쪽 클릭으로 새파일을 생성해도 된다.

import React, { Component } from 'react';

class NewComponent extends Component {
    render() {
        return (
            <div>새로운 컴포넌트</div>
        );
    }
}

export default NewComponent;

01.5.1.2. 모듈 내보내기 및 불러오기

내보내기
export default NewComponent;

불러오기
// App 컴포넌트에서 생성한 NewComponent를 불러와 사용한다.
import React, { Component } from 'react';
import NewComponent from './NewComponent';

class App extends Component {
    render() {
        return (
            <NewComponent/>
        );
    }
}

export default App;

코드를 저장하고 프로젝트를 실행한다.

$ yarn start 


컴포넌트를 생성하여 내보내기 및 불러오기를 하였다.
컴포넌트의 속성 값을 지닌 props를 알아보자.

01.5.2. props

propsproperties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하는 요소이다. props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서만 설정할 수 있다.

01.5.2.1. JSX 내부에서 props 렌더링

props를 렌더링할 때는 {} 안에 감싸 주면된다.
import React , { Component } from 'react';

class NewComponent extends Component {
    render() {
        return (
            <div>안녕하세요. 제 이름은 {this.props.name} 입니다.</div>
        );
    }
}

export default NewComponent;

01.5.2.2. 컴포넌트 사용할 때 props 값 설정

이번에는 우리가 만든 NewComponent의 name 속성 설정해본다. 설정하는 방법은 HTML 태그에 속성을 설정하는 것과 비슷하다.

import React, { Component } from 'react';
import NewComponent from './NewComponent';

class App extends Component {
    render() {
        return (
            <NewComponent name="React"/>
        );
    }
}

export default App;

코드를 저장하고 웹 브라우저를 체크하면 설정한 props가 웹 브라우저에 보인다.


01.5.2.3. props 기본 값 설정 : defaultProps

방금 설정한 NewComponent 에서 name 값을 없애고 저장한다.

(...)
<NewComponent/>
(...)
name의 값이 없기 때문에 '안녕하세요. 제 이름은 입니다.'라고 출력이 되었다. props 값을 지정하지 않았을 때 기본 값으로 설정하는 defaultProps 를 알아보자.

import React , { Component } from 'react';

class NewComponent extends Component {
    render() {
        return (
            <div>안녕하세요.  이름은 {this.props.name} 입니다.</div>
        );
    }
}

// defaultProps를 설정하는 기본적인 방법
NewComponent.defaultProps = {
    name: '기본 이름'
}

export default NewComponent;
defaultProps 를 설정하는 또 다른 방법은 클래스 내부에서 정의하는 것이다. 이 방법은 일반적인 ES6 문법에서는 작동하지 않고, ES6 stage-2에서 소개한 transform-class-properties 문법으로 사용할 수 있다. create-react-app 으로 만든 프로젝트는 기본적으로 이 문법을 적용하기 때문에 따로 작업할 것이 없다.

import React , { Component } from 'react';

class NewComponent extends Component {
    static defaultProps = {
        name : '기본 이름'
    }
    render() {
        return (
            <div>안녕하세요.  이름은 {this.props.name} 입니다.</div>
        );
    }
}

export default NewComponent;
앞서 제시한 두 코드의 차이점은 없다. 빌드 작업에서 바벨을 통해 ES5 형태의 코드로 변환할 때, 결국 동일한 결과를 보인다.

01.5.2.4. props 검증 : propTypes

컴포넌트의 필수 props를 지정하거나 props 타입(Type)을 지정할 때는 propsTypes를 사용한다. 컴포넌트의 propsTypes를 사용하려면 우선 코드 위쪽에 propTypesimport해야한다.

yarn 을 이용해 prop-types 를 설정한다.

$ yarn add prop-types

코드를
import React , { Component } from 'react';
import PropTypes from 'prop-types';

class NewComponent extends Component {
    static defaultProps = {
        name : '기본 이름'
    }
    render() {
        return (
            <div>안녕하세요.  이름은 {this.props.name} 입니다.</div>
        );
    }
}

NewComponent.PropTypes = {
    name: PropTypes.string // name props 타입을 문자열로 설정한다.
}

export default NewComponent;
class 내부에서 transform-class-properties 문법을 사용하여 설정할 수 있다.

import React , { Component } from 'react';
import PropTypes from 'prop-types';

class NewComponent extends Component {
    static PropTypes = {
        name: PropTypes.string // name props 타입을 문자열로 설정한다.
    }

    static defaultProps = {
        name : '기본 이름'
    }
    render() {
        return (
            <div>안녕하세요.  이름은 {this.props.name} 입니다.</div>
        );
    }
}

export default NewComponent;
name props 타입을 문자열(string)로 설정했다. App 컴포넌트에서 NewComponentname 값으로 문자열이 아닌 숫자를 전달해보고 개발자 도구를 확인한다.

<NewComponent name={3}/>
화면에서 3이라는 값은 확인이 되지만 개발자 도구를 확인하면 메세지를 확인할 수 있다.

<NewComponent name="React"/>
로 코드를 수정 후 다음으로 이어간다.

※ name의 3이라는 값을 {}으로 감싸야한다. 문자열 종류 외의 값을 컴포넌트에 전달할 때는 {}로 감싸야한다.

01.5.2.5. propTypes 설정

이름 설명
array 배열
bool 참,거짓
func 함수
number 숫자
object 객체
string 문자열
symbol ES6 문법의 심벌 객체
node 렌더링할 수 있는 모든 것(숫자, 문자, element 또는 이들로 구성된 배열)
element 리액트 요소
oneOf(['A','B']) 주어진 배열 요소 중 하나
oneOfType([React.PropTypes.string, React.PropTypes.number]) 주어진 배열 안의 종류 중 하나
arrayOf(React.PropTypes.string) 주어진 종류로 구성된 배열
objectOf(React.PropTypes.string) 주어진 종류의 값을 가진 객체
shape({name: React.PropTypes.string, age: React.PropTypes.number}) 주어진 스키마를 가진 객체
any 아무 종류


위 키워드들을 PropTypes.array 로 사용할 수 있다.
또한 필수 요소일 경우  PropTypes.bool.isRequired 같은 방식으로 사용할 수 있다.

defaultPropspropTypes는 꼭 사용해야 하는가?
필수 사항은 아니지만 React를 이용해 프로젝트를 진행할 경우, 다른 개발자와 협업을 한다면 해당 컴포넌트에 어떤 props가 필요한지 쉽게 알 수 있기 때문에 개발 능률을 올릴 수 있다.

01.5.3. state

컴포넌트 내부에서 읽고 또 업데이트할 수 있는 값을 사용하려면 state를 써야 한다. 이것은 언제나 기본 값을 미리 설정해야 사용할 수 있으며, this.setState() 메서드로만 값을 업데이트해야한다.

01.5.3.1 컴포넌트의 생성자 메서드 : constructor()

state 초기값은 컴포넌트의 생성자 메서드인 constructor 내부에서 설정한다. 생성자 메서드는 컴포넌트를 새로 만들 때 실행된다.

import React , { Component } from 'react';
import PropTypes from 'prop-types';

class NewComponent extends Component {
    (...)
    constructor(props) {
        super(props);
    }
    (...)
}

export default NewComponent;
앞서 만든 NewComponent는 리액트의 Component 클래스를 상속한다.
constructor 메서드를 만들어 주지 않으면 Component 클래스의 생성자 메서드를 그대로 사용한다.
직접 constructor 메서드를 작성하여 생성자 메서드에서 추가 작업을 하려면,
메서드 내부에서 부모 클래스인 Componentconstructor 메서드를 먼저 호출해야한다.
이때 super 키워드를 사용한다.
컴포넌트를 만들 때 props 값들을 사용하므로 props를 메서드의 파라미터로 전달한다.

01.5.3.2 state 초깃값 설정


    // constructor 메서드 안에서 state의 초깃값을 지정한다.
    constructor(props) {
        super(props);
        this.state = {
            number: 0
        }
    }

01.5.3.3 JSX 내부에서 state 렌더링

이제 number 값을 JSX 안에서 렌더링한다. 
이를 렌더링하는 방법은 props를 렌더링하는 방법과 비슷하다.

import React , { Component } from 'react';
import PropTypes from 'prop-types';

class NewComponent extends Component {
    (...)
    constructor(props) {
        super(props);
        this.state = {
            number: 0
        }
    }

    render() {
        return (
            <div>
                <p>안녕하세요.  이름은 {this.props.name} 입니다.</p>
                <p>숫자 : {this.state.number}</p>
            </div>
        );
    }
}

export default NewComponent;

01.5.3.4 state 값 업데이트 : setState()

state 값을 업데이트할 때는 this.setState() 메서드를 사용한다.

// 사용방법
/* this.setState({
     수정할 필드 이름 : 값
    ,수정할 또 다른 필드 이름 : 값
}); */
    render() {
        return (
            <div>
                <p>안녕하세요.  이름은 {this.props.name} 입니다.</p>
                <p>숫자 : {this.state.number}</p>
                <button onClick={() => {
                    this.setState({
                        number : this.state.number + 1
                    });
                }}>
                더하기
                </button>
            </div>
        );
    }
버튼하나를 렌더링 하고 , 이 버튼을 클릭할 때마다 number의 값이 1씩 추가되도록 설정한다.

※ ES6의 화살표 함수(함수를 만들 때 ES6의 화살표 함수를 사용했다)

※ state 값을 업데이트할 때는 언제나 setState로만 업데이트 해야한다.
this.state.number = this.state.number + 1;
위의 코드는 잘못된 코드이다. setState() 메서드가 하는 역할은 파라미터로 전달받은 필드를 업데이트한 후 컴포넌트가 리렌더링하도록 트리거하는 것이다. 하지만 위 코드처럼 직접 접근하여 값을 수정할 경우 컴포넌트를 자동으로 리렌더링 하지 않는다. this.forceUpdate() 메서드를 호출해 강제로 리렌더링을 하게 할 수는 있으나 사용을 피해야한다.

※ 초기 state 는 constructor 에서 정의해야하지만, defaultProps와 propTypes를 정의할 때 사용한 transform-class-properties 문법으로 constructor 바깥에서 정의할 수 있다.

import React , { Component } from 'react';
import PropTypes from 'prop-types';

class NewComponent extends Component {

   static propTypes = {
      name: PropTypes.string // name props 타입을 문자열로 설정한다.
    }

    static defaultProps = {
        name : '기본 이름'
    }
    (...)
}

export default NewComponent;

props부모 컴포넌트가 설정하고, state컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트한다.

댓글

  1. ㅎㅎ 블로그도 하시는군요 잘보고 가요~ 정리가 잘되어있네요

    답글삭제

댓글 쓰기

이 블로그의 인기 게시물

01.11 리액트 컴포넌트 CSS 적용 ( CSS Module, Sass, styled-components )

01.9 React 컴포넌트 라이프사이클

01.7 React ref (DOM에 이름 달기)