[React] Component

youngminss·2021년 8월 27일
0

React

목록 보기
3/7

개요

React 에서 Component 를 사용하는 방법에는 크게 1. Class Component, 2. Functional Component 가 존재하는 것은 알고 있을 것이다.
이번 포스팅에서는 주로 사용하던 Functional Component 에서보다 Class Component 에서 지나쳤던 내용 위주로 정리한다.

본론

Props

props 기본값 설정 : defaultProps

부모 컴포넌트에서 자식 컴포넌트로 props 값을 따로 지정하지 않았을 때 보여 줄 기본값을 설정하는 것이다.


// App.js
import React, { Component } from "react";
import MyComponent from "./MyComponent";

class App extends Component {
  render() {
    return (
      <div className="container">
        <MyComponent />
      </div>
    );
  }
}

export default App;

// MyComponent.js
import React, { Component } from "react";

class MyComponent extends Component {
  render() {
    return (
      <div>
        My "{this.props.name}" Component Container 생성
        <br />
        제가 좋아하는 숫자는 {this.props.favoriteNumber} 입니다.
      </div>
    );
  }
}

MyComponent.defaultProps = {
  name: "기본 이름",
  favoriteNumber: 3,
};
  • App.js 에서 MyComponent 컴포넌트를 import 해서 렌더링을 했다.
  • App.jsMyComponent 컴포넌트에서 name, favoriteNumber 에 대한 props 를 넘겨주지 않았다.
  • 이럴 경우, MyComponent 컴포넌트 내부에서 defaultProps 를 위에 코드와 같이 설정해놓으면, props 로 값을 넘기지 않아도, 해당 컴포넌트에서 사용하는 props 에 대해 기본 값으로 사용할 수 있다.

태그 사이에 내용을 보여주는 Children

리액트 컴포넌트를 사용할 때 컴포넌트 태그 사이의 내용을 보여 주는 props이다.

// App.js
import React, { Component } from "react";
import MyComponent from "./MyComponent";

class App extends Component {
  render() {
    return (
      <div className="container">
        <MyComponent>React!!</MyComponent>
      </div>
    );
  }
}

export default App;
// MyComponent.js
import React, { Component } from "react";

class MyComponent extends Component {
  render() {
    return (
      <div>
        My "{this.props.name}" Component Container 생성
        <br />
        children 값은 {this.props.children} 입니다.
        <br />
        제가 좋아하는 숫자는 {this.props.favoriteNumber} 입니다.
      </div>
    );
  }
}

MyComponent.defaultProps = {
  name: "기본 이름",
  favoriteNumber: 3,
};
  • App.js 에서 MyComponent 컴포넌트를 Self Closing 방식이 아닌, 태그 사이에 내용 이 존재하면(텍스트 && 태그도 상관없음)
  • MyComponent 에서 props.children 으로 사용가능

비구조화 할당(Destructuring, 분해할당) 을 통한 props 내부 값 추출하기

클래스 컴포넌트 의 경우, props 값을 조회할 때마다 props.속성명1, props.속성명2 ... 이런 식으로 앞에 매번 props. 키워드를 앞에 붙여줘야 된다.
이 방식을 좀 더 간편하게 할 수 있는 방식이 있다.

// MyComponent.js
import React, { Component } from "react";

class MyComponent extends Component {
  render() {
    // Destructuring(분해할당)
    const { name, favoriteNumber, children } = this.props;
    return (
      <div>
        My "{name}" Component Container 생성
        <br />
        children 값은 {children} 입니다.
        <br />
        제가 좋아하는 숫자는 {favoriteNumber} 입니다.
      </div>
    );
  }
}

MyComponent.defaultProps = {
  name: "기본 이름",
  favoriteNumber: 3,
};

export default MyComponent;
  • Destructuring 을 사용할 경우, 더 이상 클래스 컴포넌트 props 에 대해 앞에 this.props. 을 붙이지 않아도 됨으로 간략화 할 수 있다.

propTypes 를 통한 props 검증

컴포넌트의 필수 props를 지정하거나 props타입(type) 을 지정할 때는 propTypes 를 사용한다.

// MyComponent.js
import React, { Component } from "react";
import PropTypes from "prop-types";	// PropTypes import

class MyComponent extends Component {
  render() {
    const { name, favoriteNumber, children } = this.props;
    return (
      <div>
        My "{name}" Component Container 생성
        <br />
        children 값은 {children} 입니다.
        <br />
        제가 좋아하는 숫자는 {favoriteNumber} 입니다.
      </div>
    );
  }
}

MyComponent.defaultProps = {
  name: "기본 이름",
  favoriteNumber: 3,
};

// propTypes
// 각 props 에 대해 PropTypes.타입 형식으로 지정가능하다.
MyComponent.propTypes = {
  name: PropTypes.string,
  favoriteNumber: PropTypes.number.isRequired,
  children: PropTypes.node,
};

export default MyComponent;
  • propsTypes 으로 설정한 타입에 맞지 않게 값을 넘겨 받아 사용할 경우, 경고를 보여준다.

PropTypes 에 대한 것은 확인해야 할 것이 더 있다.

예를 들어

  • isRequired 설정

  • PropTypes 종류에는 array, arrayOf, bool, func , number, object, string, symbol, node, instanceOf, oneOf, oneOfType([React.PropsTypes.string, PropTypes.number]), objectOf(React.PropTypes.number) 등이 있다.

  • React.PropTypes 공식문서

앞서 설명한 defaultProps, PropTypes 는 필수는 아니다.
하지만, 큰 규모의 프로젝트의 경우, 특히 다른 개발자들과 협업하는 과정이 있다면, 해당 컴포넌트에 어떤 props 가 필요한지 쉽게 알 수 있어 개발 능률이 좋아질 수 있다.

State

(Class) 클래스형 컴포넌트 state

import React, { Component } from "react";

class Counter extends Component {
  constructor(props) {
    super(props);
    // state 초기값 설정하기
    this.state = { 
   	  number: 0
    }
  }
  render() {
    const { number } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h2>바뀌지 않는 값 : {fixedNumber}</h2>
        <button
          onClick={() => {
            // this.setState 를 사용하여 state 에 새로운 값을 넣을 수 있다.
            this.setState({ number: number + 1 });       
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;
  • 위에 예제에서 클래스 컴포넌트 에서 확인 해볼 것은
  • constructor : 컴포넌트 생성자 메서드, 작성 시 super 키워드 반드시 필요
  • 현재 클래스 컴포넌트가 상속받고 있는 React.Component 의 생성자 함수를 호출하는 것이다.

클래스 컴포넌트에서 state객체형식이어야 한다.

  • state 객체 안에는 여러 값이 존재할 수 있다.
  • 여러 값이 존재해도, this.setState({ 키 : 새로운 값 }) 업데이트 가능하다.

(Class) state 를 constructor 에서 꺼내기

import React, { Component } from "react";

class Counter extends Component {
  // state 를 constructor 밖으로 꺼냄
  state = {
    number: 0,
    fixedNumber: 0,
  };
  render() {
    const { number, fixedNumber } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h2>바뀌지 않는 값 : {fixedNumber}</h2>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

(Class) this.setState 에 객체 대신 함수 인자 전달하기 (비동기 제어)

this.setState 를 사용하여 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트 된다.

// 비동기 처리없이, 이벤트 한번에 state 두 번 변경 시
import React, { Component } from "react";

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

  render() {
    const { number, fixedNumber } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h2>바뀌지 않는 값 : {fixedNumber}</h2>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
            this.setState({ number: this.state.number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;
// state 변경, 비동기 처리(= 객체 대신에 "함수"를 인자로 넘겨준다.)
import React, { Component } from "react";

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

  render() {
    const { number, fixedNumber } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h2>바뀌지 않는 값 : {fixedNumber}</h2>
        <button
          onClick={() => {
            this.setState((prevState) => {
              return {
                number: prevState.number + 1,
              };
            });
            this.setState((prevState) => {
              return {
                number: prevState.number + 1,
              };
            });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

(Class) this.setState 가 끝난 후 특정 작업 실행하기 (비동기 제어)

setState 를 사용하여 값을 업데이트하고 난 다음에 특정 작업을 하고 싶을 때는 setState 의 두 번째 파라미터로 콜백함수(callback) 를 등록하여 작업을 처리하면, 동기적으로 처리가 가능하다.

// this.setState 에 두 번째 파라미터로 callback 함수를 전달
import React, { Component } from "react";

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

  render() {
    const { number, fixedNumber } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h2>바뀌지 않는 값 : {fixedNumber}</h2>
        <button
          onClick={() => {
            this.setState({ number: number + 1 }, () => {
              console.log("방금 setState 호출 되었습니다.");
              console.log(this.state);
            });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

🔍 기타 사항

  • 클래스형 컴포넌트든 함수형 컴포넌트든 state 값을 바꾸어야 할 때는 setState 혹은 useState 를 통해 전달받은 세터 함수를 사용해야 한다.
  • 배열이나 객체를 업데이트해야 할 때는 객체 사본을 만들고, 그 사본에 값을 업데이트한 후, 그 사본의 값을 setState 혹은 세터함수를 통해 업데이트해야 한다.
  • props 를 사용한다고 값이 무조건 고정적이지는 않는다.
  • 부모 컴포넌트의 state를 자식 컴포넌트의 props로 전달하고, 자식 컴포넌트에서 이벤트가 발생할 때, 부모 컴포넌트의 메서드를 호출하면 props 도 유동적으로 사용할 수 있다.

결론

이번 포스팅에서는 주로 다루지 않았던 Class Component 를 주로, 그것도 대부분 기본적인 내용만 살펴봤다. 이후에는 다루지 않았던 Functional Component 에 대해 더욱 자세히 살펴본다. (현재 React 는 hooks 의 시대이다.)


참고

개념

  • 책 [ 리액트를 다루는 기술 ] 을 기반으로 작성하였습니다.
profile
머쓱이를 좋아합니다 😃

0개의 댓글