Client/React.js

[React.js] Props / State: react에서 data를 다루는 방법

ooeunz 2020. 7. 26. 23:07
반응형

※ 해당 포스팅은 state / props에 대한 어느 정도 기본적인 지식이 있다는 전제로 상태와 속성으로 data를 관리하는 react의 특성을 중점적으로 살펴보도록 하겠습니다.

 

props와 state는 react component에서 데이터를 다루는 대표적인 두 가지 방법입니다. Props와 State를 요약해서 설명하자면 props는 부모 컴포넌트가 자식 컴포넌트에게 주는 데이터이고 해당 데이터는 직접적으로 수정할 수 없는 값입니다. 반면 state는 컴포넌트 내부에서 가지고 있는 값으로써 변경할 수 있는 값입니다. props와 state는 react에서 가장 핵심적인 개념 중 하나입니다. 나중에 다뤄보게 될 redux와 같은 전역 데이터를 관리해주는 라이브러리도 결국 이 props와 state를 이용해 구현되게 됩니다.

 

 

 

State

react에서는 UI의 데이터는 반드시 props와 state로 관리되어야 합니다. 이는 데이터를 일관성 있게 다루고자 하는 목적도 있지만 가장 중요한 이유는 react life cycle이 props와 state의 변경을 기준으로 화면을 갱신하기 때문입니다. 아래의 코드는 state 값을 변경하는 함수를 버튼에 적용하는 코드입니다.

import React from 'react';

class StateSample extends React.Component {
  state = { myName: 'noah' };
  onClick = () => {
    this.setState({ myName: 'ooeunz' });
  };
  render() {
    return (
      <button onClick={this.onClick}>
        내 이름은 {this.state.myName}
      </button>
    );
  }
}

export default StateSample;

위의 코드는 버튼을 누르면 '내 이름은 noah'에서 '내 이름은 ooeunz'로 바뀌는 간단한 JSX코드입니다. 위의 코드를 보면 특이하게 state 안에 myName이라는 프로퍼티를 할당하고 onClick 메서드에서 myName 값을 바꾸기 위해서 setState라는 함수를 사용한 것을 볼 수 있습니다.

 

일반적으로 javascript를 사용하는 사람은 단순히 state.myName = 'ooeunz'와 같은 코드를 생각해냈을지 모릅니다. 그런데 특이하게 위의 코드에서는 setState라는 함수를 사용해서 mytName이라는 프로퍼티를 새롭게 할당했습니다. setState란 뭘까요?

 

setState란 React의 불변성을 지키며 state의 값을 변경하기 위한 리액트 함수입니다. 리액트에서는 모든 상태 값들을 불변성을 유지하며 관리하게 되는데, 이렇게 불변성을 유지하는 것은 virtual-dom이 real dom과의 차이를 알아내기 위한 이유가 있습니다.

 

만약 객체가 직접적으로 값이 변경되게 된다면 변경된 객체를 찾기 위해 실제 돔과 가상 돔 전체 트리를 비교하며 변경사항을 감지해야 합니다. 하지만 불변 객체를 사용하면 변화를 감지하는 것이 상담이 쉬워집니다. 단순히 참조하고 있는 불변 객체가 이전 객체와 다른지를 얕은 평가 만으로 확인할 수 있기 때문입니다.

 

또한 상태 값을 불변 객체로 유지하는데에 가장 큰 장점은 React에서 리 렌더링 시기를 결정하는 데에 도움을 준다는 것입니다. 위에 언급한 대로 객체가 변경되었는지 쉽게 판단할 수 있기 때문에 이를 바탕으로 컴포넌트가 다시 렌더링할지를 결정할 수 있게 됩니다. 

 

setState는 이러한 리액트의 특성을 반영한 메서드로, setState 메서드가 호출되면 상탯값을 변경하고 해당 컴포넌트를 다시 렌더링 하게 됩니다.

 

 

Props

props는 부모 컴포넌트에서 자식 컴포넌트로 전달해 주는 데이터 입니다. 아래에 간단한 예시 코드를 통해 props에 대해서 살펴보도록 하겠습니다.

import React from 'react';

function Title(props) {
  return <p>{props.title}</p>;
}

export default Title;
import React from 'react';
import Title from './Title';

class Todo extends React.Component {
  state = { count: 0 };
  onClick = () => {
    const { count } = this.state;
    this.setState({ count: count + 1 });
  };
  render() {
    const { count } = this.state;
    return (
      <div>
        <Title title={`현재 카운트: ${count}`} />
        <button onClick={this.onClick}>증가</button>
      </div>
    );
  }
}

export default Todo;

위의 코드에서 Title 컴포넌트 (함수형 컴포넌트: React 16.9 version부터 함수형 컴포넌트도 state 값을 가질 수 있다)는 부모 컴포넌트 Todo에서 title이라는 props 값을 받습니다. 따라서 Title 컴포넌트는 부모 컴퍼넌트가 렌더링 될 때마다 같이 렌더링 되게 되므로, title 속성 값의 변경 사항이 바로 화면에 반영됩니다.

 

그런데 Title 컴포넌트는 부모 컴퍼넌트가 렌더링 될 때마다 자동으로 같이 렌더링 된다고 했는데, 만약 title 속성 값이 변경되지 않았음에도 자꾸만 새롭게 렌더링 된다면 의미 없는 자원의 소비로 이어지게 됩니다. 이와 같이 title props 값이 변경될 때만 렌더링 하기를 원한다면 React.memo 또는 React.PureComponent를 이용해서 props 값이 변경될 때만 렌더링을 하도록 설정할 수 있습니다.

 

아래는 React.memo와 React.PureComponent를 사용한 예시 코드입니다. 코드에서 알 수 있듯이 함수형 컴포넌트에서는 React.memo를 사용하고 클래스형 컴포넌트에서는 React.PureComponent를 사용합니다.

function Title(props) {
  return <p>{props.title}</p>
}
export default React.memo(Title);

export default class Title extends React.PureComponent {
  render() {
    return <p>{this.props.title}</p>;
  }
}

 

반응형