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

Lynn·2021년 7월 17일
0

React

목록 보기
6/17
post-thumbnail

함수형 vs. 클래스형?

함수형 컴포넌트
비교적 선언하기 편함
메모리 자원을 더 적게 사용함

클래스형 컴포넌트
state, 라이프사이클 API 사용 가능
임의 메서드 정의 가능

하지만 리액트 업데이트 이후 Hooks 도입으로 함수형 컴포넌트도 클래스형 컴포넌트처럼 사용할 수 있게 됐다...! (나중에 자세히 다룰 것)

컴포넌트 코드의 구성

// src/MyComponent.js
import React from 'react';

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

위는 함수형 컴포넌트로, 화살표함수를 사용해 작성해주었다. 마지막 줄에서 export로 모듈을 내보내 다른 파일에서 이 컴포넌트를 사용할 수 있도록 한다. 예를 들어 App.js에서 쓴다면...

// App.js
import React, { Component } from 'react';
import MyComponent from './MyComponent';
 
class App extends Component {
  render() {
  	return <MyComponent />;
  }
};
 
export default App;

App.js는 클래스형으로 작성했다. 클래스형은 컴포넌트를import { Component } from 'react'; 혹은 class App extends React.Component 으로 상속받아 정의할 수 있다.
render() 메서드는 클래스 컴포넌트에서 반드시 구현돼야하는 유일한 메서드로, this.propsthis.state의 값을 활용하여 return한다.

Props

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

우선 MyComponent를 수정하여 name이라는 props를 렌더링하도록 설정해 보자. props값은 컴포넌트 함수의 파라미터로 받아 와서 사용할 수 있다.

// src/MyComponent.js
import React from ‘react‘;

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

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

export default MyComponent;

이렇게 props를 정의해두고 위 컴포넌트가 필요로 하는 props값을 App.js에서 지정해 주면 된다. 사용하는 곳에서 지정해 주지 않으면, defaultProps에서 설정한 값이 들어갈 것이다.

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

props.children

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

// App.js
import React from 'react';
import MyComponent from './MyComponent';
 
const App = () => {
  return <MyComponent>리액트</MyComponent>;
};
 
export default App;

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

<MyComponent>태그 사이에 있던 '리액트'가 props.children으로 넘어간다.

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

비구조화 할당 문법은 객체에서 값을 추출하는 것을 말한다. 다시 말해 props.name, props.children 이렇게 호출해야 했던 것들을 props 객체에서 값을 추출(비구조화)함으로써 아래와 같이 코드를 간단하게 만들 수 있다.

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

propTypes

컴포넌트의 필수적인 props를 지정하거나 props의 타입을 지정할 때는 propTypes를 사용한다. import 구문을 필요로 한다.

import React from ‘react‘;
import PropTypes from ‘prop-types‘;

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

MyComponent.propTypes = {
  name: PropTypes.string.isRequired,
  children: PropTypes.number
};

export default MyComponent;

이렇게 지정을 해 두면 props.name이 문자열이 아니거나, 값이 지정되지 않거나(isRequired일 때), props.children이 숫자가 아니면 콘솔창에서 오류가 뜬다. 이런 식으로 검증 가능!

PropTypes 종류

  • array, bool, func, number, object, string
  • arrayOf(other) other로 이루어진 배열
  • symbol ES6의 Symbol
  • node 렌더링할 수 있는 모든 것(숫자, 문자열, JSX코드, props.children)
  • instanceOf(class) 특정 클래스의 인스턴스
  • oneOf(['a','b']) 주어진 배열 요소 중 값 하나
  • oneOfType([PropTypes.string, PropTypes.instanceOf(class)]) 주어진 배열 안 종류 중 하나
  • objectOf(PropTypes.number) 특정 타입의 프로퍼티 값들을 갖는 객체
  • shape({ name: PropTypes.string, num: PropTypes.number }) 특정 형태를 갖는 객체
  • any 아무 종류

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

class MyComponent extends Component {
  render() {
    const { name, favoriteNumber, children } = this.props; // 비구조화 할당
    return (
      <div>
        안녕하세요, 제 이름은 {name}입니다. <br />
        children 값은 {children}
        입니다.
        <br />
        제가 좋아하는 숫자는 {favoriteNumber}입니다.
      </div>
    );
  }
}

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

MyComponent.propTypes = {
  name: PropTypes.string,
  favoriteNumber: PropTypes.number.isRequired
};

export default MyComponent;

render 함수에서 this.props를 조회하면 된다. 아래처럼 클래스 내부에서 defaultPropspropTypes를 설정할 수도 있다.

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

class MyComponent extends Component {
  static defaultProps = {
    name: ‘기본 이름‘
  };
  static propTypes = {
    name: PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired
  };
  render() {
    const { name, favoriteNumber, children } = this.props; // 비구조화 할당
    return ();
  }
}

export default MyComponent;

state

리액트에서 state란 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다. props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이므로, 이를 바꾸려면 꼭 부모 컴포넌트에서 바꾸어 주어야 한다.

클래스형 컴포넌트의 state

클래스형 컴포넌트에서 state를 설정할 때는 아래와 같이 constructor 생성자 메소드를 작성해서 설정해줄 수 있다.

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

super(props);를 호출해 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 component 클래스가 지닌 생성자 함수를 호출해야 한다. 그 후 this.state 객체에 초기 state 값을 설정해 준다.

  state = {
    number: 0,
    fixedNumber: 0
  };

...아니면 그냥 constructor 없이 설정해도 된다.

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

render 함수를 확인해보면 button 태그에 onClickprops로 전달해서 이벤트를 설정했다. 이벤트로 설정할 함수를 넣어 줄 때는 화살표 함수 문법을 사용하여 넣어 주어야 한다. 설정된 함수 내부에서는 this.setState라는 함수를 사용해서 state 값을 변경한다. 전달된 객체 안에 들어 있는 값만 바꾸어 주기 때문에 fixedNumber는 바뀌지 않는 것!

this.setState에 객체 대신 함수 인자 전달하기

this.setState는 비동기함수이므로 아래와 같이 코드를 작성하면 +1이 두 번 되지 않는다.

onClick={() => {
  this.setState({ number: number + 1 });
  this.setState({ number: this.state.number + 1 });
}}

이를 해결하려면 아래 코드와 같이 객체 대신 함수를 인자로 넣어 주면 된다.

onClick={() => {
    this.setState(prevState => {
      return {
        number: prevState.number + 1
      };
    });
    // 위 코드와 아래 코드는 완전히 똑같은 기능을 함
    // 아래 코드는 함수에서 바로 객체를 반환한다는 의미
    // (코드블럭{} 생략, return 구문 생략)
    this.setState((prevState, props) => ({
      number: prevState.number + props
    }));
    // 업데이트하는 과정에서 prop이 필요하다면 전달
  }}

여기서 prevState는 기존 상태이고, props는 현재 지니고 있는 props를 가리킨다. 필요 없으면 위 코드와 같이 prevState만 전달해도 된다.

profile
wanderlust

0개의 댓글

관련 채용 정보