Pandaman Blog

[React.js] 리액트 state와 setState 본문

Front end/React

[React.js] 리액트 state와 setState

oyg0420 2020. 3. 12. 22:55

목차

1. state란?

2. setState

3. 이벤트 설정

오늘은 리액트 프로젝트를 진행하면서 필수적이고 기본적인 객체인 state와 함수 setState에 대해 알아보겠습니다.

state란

state란 렌더링 결과물에 영향을 주는 정보

리액트 공식 홈페이지에서는 state에 대해 위와 같이 말합니다. 즉, state는 컴포넌트가 마운트 될 때 기본값을 갖게 되고, 우리는 이 state를 활용해 데이터를 변화시켜줄 수 있습니다.

아래의 예제를 살펴보겠습니다. 참고로 아래의 App.js는 ReactDom.render 함수에 첫 번째 인자에 전달될 컴포넌트입니다.

import React from 'react';

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'pandaman',
      age: 31,
      job: 'developer',
    };
  }

  render() {
    const { name, age, job } = this.state;
    return (
      <div>
        <div>name: {name}</div>
        <div>age: {age}</div>
        <div>job: {job}</div>
      </div>
    );
  }
}

위의 코드는 클래스형 컴포넌트입니다. react를 사용하기 앞서 class에 extends 키워드를 통해 상속받을 클래스(React.Component)를 명시합니다. constructor 즉 생성자 내부에 super() 연산자를 사용해 React.Component를 상속받아 this.state을 사용할 수 있습니다.

this.state라는 코드를 확인해 봅시다.

this.state = {
      name: 'pandaman',
      age: 31,
      job: 'developer',
    };

state가 객체라고 한 이유를 이제 아시겠죠?

state 객체에 속성과 값을 정의할 수 있습니다.

npm start또는 yarn start로 화면을 띄어보겠습니다.

초기화한 값이 노출되시는 걸 확인하셨나요?

초기화된 state의 속성의 렌더링 결과

아래에서는 state을 변경하기 위한 함수를 소개해 드리겠습니다.

setState

state를 변경하기 위해서는 setState() 함수를 사용해야 합니다. 그리고 setState 함수는 비동기로 작동합니다.
즉, setState() 함수를 사용해서 state를 업데이트하더라도 즉시 반영되지 않는다는 뜻입니다.

1) setState(updater[, callback])
2) updater: (state, props) => stateChage

첫 번째 인수 updater 함수로 전달된 state와 prop는 최신의 값입니다. 최신의 값을 이용해, 상태를 업데이트하시면 됩니다.
두 번째 인수 callback은 setState의 실행이 완료되고 컴포넌트가 렌더링 된 뒤에 실행될 함수입니다. 생략이 가능합니다.

바로 만들어 볼까요?

handleAgeIncrementClick = () => {
  this.setState((state) => { age: state.age + 1 })
}

현재 state에서 age속성을 1씩 증가시키는 것을 확인할 수 있습니다.

또한, setState 함수에 첫 번째 인수에 객체를 전달하여 state를 업데이트할 수 있습니다.

handleAgeIncrementClick = () => {
    const { age } = this.state;
    this.setState({ age: age + 1 });
  };

첫 번째 인수에 함수를 할당해 state를 업데이트하는 동작과 동일한 결과를 나타냅니다.

추가적으로 setState의 두 번째 인수 callback도 할당해보겠습니다.

  handleAgeIncrementClick = () => {
    this.setState(
      prevState => ({
        age: prevState.age + 1
      }),
      () => console.log(this.state.age)
    );
  }

age 상태가 업데이트되면 callback이 작동하여 업데이트된 age가 로그에 남는 것을 확인할 수 있습니다.

지금까지 상태를 업데이트하는 방법에 대해 배웠습니다. 이제 활용만 해보면 되겠군요.

이벤트 설정

render 함수에서 event를 설정하는 방법에 대해 알아보겠습니다.

(추가적으로 name과 job을 입력할 수 있는 input을 추가했습니다. 그리고 onChange 이벤트가 발생했을 때 동작하는 함수 handleNameChange, handleJobChange 도 추가적으로 생성했습니다.)

import React from "react";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "pandaman",
      age: 31,
      job: "developer"
    };
  }

  handleAgeIncrementClick = () => {
    this.setState(
      prevState => ({
        age: prevState.age + 1
      }),
      () => console.log(this.state.age)
    );
  };

  handleNameChange = event => {
    this.setState({ name: event.target.value });
  };

  handleJobChange = event => {
    this.setState({ job: event.target.value });
  };

  onClickEventHandler = () => {
    this.setState({
      name: "pandaman",
      age: 31,
      job: "developer"
    });
  };

  render() {
    const { name, age, job } = this.state;
    return (
      <div>
        <div>
          name: <input type="text" value={name} onChange={this.handleNameChange} />
        </div>
        <div onClick={this.onAgeHandler}>age: {age}</div>
        <div>
          job: <input type="text" value={job} onChange={this.handleJobChange} />
        </div>
        <button type="button" onClick={this.handleAgeIncrementClick}>
          reset
        </button
      </div>
    );
  }
}

<input type="text" value={name} onChange={this.handleNameChange} />를 보면 기존에 HTML에서 입력했던 방식과 사뭇 다르다는 것을 확인할 수 있습니다.

어떤 부분이 다를까요?

바로 이벤트 속성과 이벤트 핸들러의 작성방식이 다릅니다.

1) React에서는 이벤트 속성에 대해 camelCase로 작성합니다. onclick -> onClick 으로 변경되어야 합니다.
2) 이벤트 속성의 함수는 문자열이 아닌 {this.handleNameChange} 또는 {(event) => this.handleNameChange(event)}로 작성해야 합니다.

{this.handleNameChange}로 작성이 가능한 이유는 handleNameChange Arrow Function으로 작성되었기 때문에 bind(this)를 사용할 필요가 없습니다.

참고로, Arrow Function 내부에서의 this는 자신을 감싼 객체를 나타냅니다. 만약 handleNameChange 함수선언식으로 되어있고, {this.handleNameChange}로 작성된다면, this는 전역이므로 this.setState를 호출할때 에러가 발생할 것 입니다. handleNameChange 함수선언식으로 작성되었다면 {(error) => this.handleNameChange(error)}로 작성해야합니다.

자! 이제 우리는 이벤트가 발생했을 때 핸들러를 통해 state를 업데이트하는 방법까지 배웠습니다.

최종적인 화면은 아래와 같습니다.

최종 화면

다음 시간에는 Component Life cycle에 대해 알아보도록 하겠습니다.

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음

Comments