FrameWork/React

리액트 State와 useState 사용하기

jheaon 2023. 7. 9. 11:02

 

오늘은 리액트 State에 대해서 알아보자.

 


 

일단 아래코드를 살펴보자 아래 코드는 클릭 이벤트가 발생했을 때 title이 바뀌는 코드이다. 

 

 

🖥️ ExpensItem.js

import "./ExpenseItem.css";

function ExpensItem(props) {
  let title = props.title;

  const handleClick = () => {
    title = "안녕하세요!";
  }


  return (
    <div className="expense-item">
      <div>{props.date.toISOString()}</div>
      <div clasName="expense-item__description">
        <h2>{title}</h2>
        <div className="expense-item__price">${props.amount}</div>
      </div>
      <button
        onClick={handleClick}
      >
        hello
      </button>
    </div>
  );
}

export default ExpensItem;

하지만 버튼을 눌렀을 경우 버튼 이벤트인 handleClick이 작동하지 않았음을 알 수 있다. 왜 작동하지 않는 걸까? 이는 리액트의 작동방식과 연관이 있다.

 

일단 ExpensItem 컴포넌트는 일반적인 함수형이며 이 함수에서 특별한 점은 JSX을 반환한다는 것이다. 리액트는 이 함수를 불러일으킨 다음 함수의 결괏값을 랜더링 하는 방식으로 진행하는데 여기서 중요한 점은 함수를 부르고 다시 그 함수를 재호출 하지 않는다는 점이다. 따라서 함수 내에서 어떠한 이벤트가 발생한다 한들 리액트에서 그 함수를 재호출 하지 않는 이상 그 변하는 값을 화면에 출력할 수 없다. 이러한 점을 개선시키기 위해서 나온 개념이 "State"라는 개념이다. 

 

State

state는 컴포넌트에 대한 데이터 또는 정보를 포함하는 데 쓰이는 리액트 내장 객체를 의미한다. 컴포넌트 상태는 시간이 지남에 따라 변경될 수 있고 변경될 때마다 컴포넌트가 다시 랜더링 하는 형태로 작동한다. state변경은 사용자 작업 또는 시스템 생성 이벤트에 대한 응답으로 발생할 수 있다. 

 

아래는 state을 사용하여 title값을 바꾸는 코드이다. 

 

🖥️ ExpensItem.js

import React, { useState } from "react";
import "./ExpenseItem.css";

function ExpensItem(props) {
  const [title, setTitle] = useState(props.title);

  const clickHandler = () => {
    setTitle("updated!");
    console.log("clicked");
  };

  return (
    <div className="expense-item">
      <div>{props.date.toISOString()}</div>
      <div clasName="expense-item__description">
        <h2>{title}</h2>
        <div className="expense-item__price">${props.amount}</div>
      </div>
      <button onClick={clickHandler}>hello</button>
    </div>
  );
}

export default ExpensItem;

 

state을 사용하기 위해서는 { useState } 훅을 이용하여 state을 사용한다. 사용하는 방법은 다음과 같다. 

  • import 구문을 통해 { useState }을 가져온다. 
  • useState()을 호출하면 다음과 같은 값을 반환한다. 
    const [ state, setState ] = useState(initialState)
    const [ 상태, 세터함수 ] = useState(초기값) 
    배열의 첫 번째 요소는 현재 상태를 의미하고, 두 번째 요소는 상태를 바꾸어주는 setState함수라 리턴된다. 
    따라서 해당 state값을 바꿔주기 위해서는 setState(바꾸고 싶은 값)을 넣어 변경한다. 

위의 코드를 보면 useState(props.title)을 통해 useState함수를 불러와 현재 상태 값에는 title, 상태를 바꿔주는 setState에는 setTitle을 넣어주었다. 내가 원하는 것은 클릭 시 title 값이 바뀌는 것이므로, clickHandler에 setTitle을 통해 title 값을 바꿔주는 것을 확인할 수 있다. 

 

 

 

 

이전 상태에 의존하는 상태 업데이트

리액트 에서는 prevState 라는 개념이 있다. setState로 상태 값을 여러번 변경 하려고 할때마다 즉각적으로 state 에 변경된 상태값을 적용시키지 않고, 상태값이 변경 될 때 마다 렌더링을 시켜주는데, 매번 상태값을 즉각적으로 변경시킬때 마다 렌더링이 된다면 매우 비효율적이다. 따라서 이런 상황을 타파하기 위해서 setState으로 미리 변경된 상태값을 바로 땡겨와서 변경될 state에 적용시키는 방법이 있다. 

 

다음은 그 예를 나타낸 코드이다. 

 

- main.js

import { useState } from "react";

const StatePrev = () => {
  const [count, setCount] = useState(0);
  const onClickCount = () => {
    setCount( count + 1);
    setCount( count + 1);
    setCount( count + 1);
    setCount( count + 1);
  };
  return (
    <div>
      <div>현재카운트:{count}</div>
      <button onClick={onClickCount}>카운트 올리기</button>
    </div>
  );
};
export default StatePrev;

 

위 코드에서 처럼 여러번 setCount(count+1)을 해주었을때 현재 count 는 정상적으로 증가를 하지 않는다. setCount 가 여러번 실행되면서 카운트가 누적되는것 처럼 보이지만, 실질적으로는 setCount로 1증가 하고 다시 setCount로 1증가 이런식으로 흐름이 진행됨으로 실질적으로 count 에는 1 만 증가되는 현상이 있다. 그렇다면 해당 부분을 해결하기 위해서는 어떻게 해야할까?

 

이는 useState 동작 원리를 위해 안쪽 코드를 뜯어보면 방법이 찾을 수 있는데, 이전의 상태값을 가지고 콜백으로 다음 상태값에 값을 덮어씌울수 있다고 한다. 

type SetStateAction<S> = S | ((PreState: S) => S);

 

 

따라서 해당 코드를 통해 윗 예제 코드를 변경해본다면 아래와 같이 수정이 가능하다. 

 

- main.js

 

import { useState } from "react";

const StatePrev = () => {
  const [count, setCount] = useState(0);
  const onClickCount = () => {
    setCount((count) => count + 1);
    setCount((count) => count + 1);
    setCount((count) => count + 1);
    setCount((count) => count + 1);
  };
  return (
    <div>
      <div>현재카운트:{count}</div>
      <button onClick={onClickCount}>카운트 올리기</button>
    </div>
  );
};
export default StatePrev;

'FrameWork/React'의 다른글

  • 현재글 리액트 State와 useState 사용하기

관련글