본문 바로가기

리액트

State

state는 컴포넌트 내부에서 바뀔 수 있는 값을 의마한다.

props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있다. 

props를 바꾸려면 부모 컴포넌트에서 바꿔주어야 한다. 

 

state는 클래스형 컴포넌트가 지니고 있는 state와 함수형 컴포넌트의 useState가 있다. 

 

클래스형 컴포넌트의 state

 

Counter.js파일을 src 디랙터리에 생성해보자.

import React, { Component } from ‘react‘;
 
class Counter extends Component {
  constructor(props) {
    super(props);
    // state의 초깃값 설정하기
    this.state = {
      number: 0
    };
  }
  render() {
    const { number } = this.state; // state를 조회할 때는 this.state로 조회합니다.
    return (
      <div>
        <h1>{number}</h1>
        <button
          // onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
          onClick={() => {
            // this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.
            this.setState({ number: number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}
 
export default Counter;

위의 파일에서 각 코드가 어떤 역할을 하는지 알아보자.

컴포넌트에 state를 설정할 때는 다음과 같이 constructor 메서드를 작성하여 설정한다.

constructor(props) {
  super(props);
  // state의 초깃값 설정하기
  this.state = {
      number: 0
    };
  }

이는 컴포넌트의 생성자 메서드인데, 클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해 주어야 한다. 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속하고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해 준다. 

 

그 다음에 this.state값에 초깃값을 설정해 주었다. 컴포넌트의 state는 객체 형식이어야 한다. 

 

하단 코드도 확인해보자.

render() {
    const { number } = this.state; // state를 조회할 때는 this.state로 조회합니다.
    return (
      <div>
        <h1>{number}</h1>
        <button
          // onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
          onClick={() => {
            // this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.
            this.setState({ number: number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}
 
export default Counter;

render함수에서 현재 state를 조회할 때는 this.state를 조회하면 된다. 

그리고 버튼 안에 onClick값을 props르 넣어주었는데, 버튼이 클릭될 때 호출시킬 함수를 설정할 수 있게 해준다. 

이벤트로 설정할 함수를 넣어 줄 때는 화살표 함수 문법을 사용하여 넣어 주어야 한다. 함수 내부에서는 this.setState라는 값을 사용하였다. 이 함수가 state값을 바꿀 수 있도록 해준다. 

 

app.js는 다음과 같다.

import React from "react";
import Counter from "./Counter";

const App = () => {
  return <Counter />;
};

export default App;

 

 

state 객체 안에 여러 값이 있을 때

state객체 안에는 여러 값이 있을 수 있다.

 

Counter를 다음과 같이 바꾸어보자.

import React, { Component } from "react";

class Counter extends Component {
  constructor(props) {
    super(props);
    //state의 초깃값 설정하기
    this.state = {
      number: 0,
      fixedNumber: 0,
    };
  }
  render() {
    const { number, fixedNumber } = this.state; //state를 조회할 때는 this.state로 조회합니다.
    return (
      <div>
        <h1>{number}</h1>
        <button
          //onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
          onClick={() => {
            //this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.
            this.setState({ number: number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

현재 state안에 다른 값을 또 추가하고, 버튼이 클릭될 때 fixedNumber값은 그대로 두고 number값만 바꿀 것이다. 

this.setState는 인자로 전달되 객체 안의 값만 바꾸어 준다.

 

앞처럼 state의 초기값을 지정하기 위해 constuctor메서드를 선언할 수도 있지만, 또 다른 방식으로 state의 초긱값을 지정해 줄 수도 있다. 

import React, { Component } from "react";

class Counter extends Component {
    //state의 초깃값 설정하기
    state = {
      number: 0,
      fixedNumber: 0,
    };
  }
  render() {
    const { number, fixedNumber } = this.state; //state를 조회할 때는 this.state로 조회합니다.
    return (
      <div>
        <h1>{number}</h1>
        <h2>바뀌지 않는 값 {fixedNumber}</h2>
        <button
          //onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
          onClick={() => {
            //this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.
            this.setState({ number: number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

 

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

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

onClick에 설정한 함수 내부에서 this.setState를 두 번 호출하면,

 onClick={() => {
            //this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.
            this.setState({ number: number + 1 });
            this.setState({ number: this.state.number + 1 });
          }}

this.setState를 두 번 사용하는 것임에도 불구하고 숫자가 1씩 더해진다.

this.setState를 사용한다고 해서 state값이 바로 바뀌지는 않기 때문이다.

 

이에 대한 해결책은 this.setState를 사용할 때 객체 대신에 함수를 인자로 넣어 주는 것이다. 

this.setState((preState, props) => {
              return{
                //업데이트 하고 싶은 내용
              }
            })

preState는 기존 상태이고, props는 현재 지니고 있는 props이다. 생략이 가능하다.

따라서 코드는 다음과 같이 수정한다. 

 

import React, { Component } from "react";

 

class Counter extends Component {

  //state의 초깃값 설정하기

  state = {

    number0,

    fixedNumber0,

  };

 

  render() {

    const { numberfixedNumber } = this.state//state를 조회할 때는 this.state로 조회합니다.

    return (

      <div>

        <h1>{number}</h1>

        <h2>바뀌지 않는 값 {fixedNumber}</h2>

        <button

          //onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.

          onClick={() => {

            //this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.

            this.setState((preState=> {

              return {

                //업데이트 하고 싶은 내용

                numberpreState.number + 1,

              };

            });

            //아래와 같은 코드이다.

            //return을 생략할 수도 있다.

            this.setState((preState=> ({

              numberpreState.number + 1,

            }));

          }}

        >

          +1

        </button>

      </div>

    );

  }

}

export default Counter;

이제는 2씩 잘 올라간다.

 

this.setState가 끝난 후 특정 작업 실행하기

setState를 사용하여 값을 업데이트 하고 난 다음에 특정 작업을 하고 싶을 때는 setState의 두 번째 파라미터로 콜백함수를 등록하여 작업을 처리할 수 있다.

 

import React, { Component } from "react";

 

class Counter extends Component {

  //state의 초깃값 설정하기

  state = {

    number0,

    fixedNumber0,

  };

 

  render() {

    const { numberfixedNumber } = this.state//state를 조회할 때는 this.state로 조회합니다.

    return (

      <div>

        <h1>{number}</h1>

        <h2>바뀌지 않는 값 {fixedNumber}</h2>

        <button

          //onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.

          onClick={() => {

            //this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.

            this.setState(

              {

                numbernumber + 1,

              },

              () => {

                console.log("방금 setState가 호출되었습니다.");

                console.log(this.state);

              }

            );

          }}

        >

          +1

        </button>

      </div>

    );

  }

}

export default Counter;

 

 

console창에 잘 호출된 것을 볼 수 있다. 

 

함수형 컴포넌트에서 useState 사용하기

여기서 Hooks라는 개념이 등장한다.

 

배열 비구조화 할당

배열 비구조화 할당은 이전에 배운 객체 비구조화 할당과 비슷하다. 배열 안에 들어 있는 값을 쉽게 추출할 수 있도록 해주는 문법이다. 

 

const array = [1,2];
const one = array[0];
const two = array[1];

//다음과 같이 바꿀 수 있다.
const array=[1,2];
const [one, two] = array;

 새 컴포넌트를 만들어서 useState를 사용해 보자. 

src 디렉터리에 Say.js라는 파일을 생성하고 다음 코드를 작성해보자. 

 

import React, { useState } from "react";

 

const Say = () => {

  const [messagesetMessage= useState("");

  const onClickEnter = () => setMessage("안녕");

  const onClickLeave = () => setMessage("잘가");

 

  return (

    <div>

      <button onClick={onClickEnter}>입장</button>

      <button onClick={onClickLeave}>퇴장</button>

      <h1>{message}</h1>

    </div>

  );

};

 

export default Say;

 

useState에 상태의 초기값을 먼저 넣어준다. 클래스형에서는 스테이트의 초기값은 객체 형태였지만, useState에서는 반드시 객체가 아니어도 상관없다. 숫자, 문자, 객체, 배열 모두 가능하다. 

 

함수를 호출하면 배열이 반환되는데, 첫 번째 원소는 현재 상태아고 두 번째 원소는 상태를 바꾸어주는 함수이다. 이 함수를 Setter함수라고 부른다.

배열 비구조화 할당을 통해 이름은 자유롭게 정해 줄 수 있다. 

 

이제 App.js를 고쳐서 확인해보자.

 

import React from "react";

import Say from "./Say";

 

const App = () => {

  return <Say />;

};

 

export default App;

 

잘 작동하는 것을 볼 수 있다. 

 

한 컴포넌트에서 useState여러 번 사용하기

useState는 한 컴포넌트에서 여러 번 사용해도 상관 없다.

 

import React, { useState } from "react";

 

const Say = () => {

  const [messagesetMessage= useState("");

  const onClickEnter = () => setMessage("안녕");

  const onClickLeave = () => setMessage("잘가");

 

  const [colorsetColor= useState("black");

 

  return (

    <div>

      <button onClick={onClickEnter}>입장</button>

      <button onClick={onClickLeave}>퇴장</button>

      <h1 style={{ color }}>{message}</h1>

      <button style={{ color"red" }} onClick={() => setColor("red")}>

        빨간색

      </button>

      <button style={{ color"green" }} onClick={() => setColor("green")}>

        초록색

      </button>

      <button style={{ color"blue" }} onClick={() => setColor("blue")}>

        파란색

      </button>

    </div>

  );

};

 

export default Say;

 

'리액트' 카테고리의 다른 글

이벤트 핸들링  (0) 2021.08.03
Hooks  (0) 2021.07.30
Props  (0) 2021.07.19
컴포넌트 생성  (0) 2021.07.18
클래스형 컴포넌트와 함수형 컴포넌트  (0) 2021.07.17