Frontend/React

React Study - 3. State

rachel_13 2023. 4. 10. 08:00

리액트의 또다른 코어 컨셉 중 하나인 State에 대해 알아보자.

 

리액트를 한 번이라도 접해본 사람이라면 "상태값"이라는 단어를 아마도 많이 들어봤을 것이다. 이 상태값인 "state"는 말 그대로 상태가 변경되는 값으로 컴포넌트 내부에서 변경될 수 있다.

 

웹 브라우저에서는 다양한 상호작용으로 인해 화면 자체에 빈번한 변화가 생긴다.

예를 들면, 폼 안에 입력 필드를 수정하면 업데이트되고, 슬라이드 되는 화면에서 "다음"버튼을 누르면 다음 슬라이드가 보이며, "장바구니에 담기"를 클릭하면 장바구니에 담기는 것들이 모두 interaction이다. 

컴포넌트들은 현재 input의 입력 값, 현재의 슬라이드 페이지, 장바구니 등을 "기억"해야 한다.

 

리액트에서는 이러한 종류의 컴포넌트 별 메모리(기억 저장소 쯤으로 해석될 수 있겠다.)를 바로 "상태(state)"라고 부른다.

 

일반적으로 선언한 로컬 변수는 렌더링 간에 유지되지 않는다. 재렌더링될 때 변경 사항을 고려하지 않기 때문에, 로컬 변수가 변경이 되어도 그 변경사항을 트래킹 하지 않는다. 즉 새 데이터로 다시 렌더링해야 한다는 것 자체를 인지하지 못하는 것이다.

 

리액트에서 새로운 데이터로 업데이트를 하기 위해서 useState Hook을 제공한다.

(* 함수형 컴포넌트를 기준으로 설명한다.)

 

1. state는 렌더링 간의 데이터를 유지시킨다.

2. state setter 함수는 변수를 업데이트하고,  컴포넌트를 다시 렌더링 하기 하여 변경사항을 뷰에 반영한다.

👉 useState를 사용해서 어떤 상태값을 선언했다는 것은, React에게 이 컴포넌트에서 상태값을 기억해! 라고 알려주는 것과 같다.

 

 

3.4 useState 사용하기

다음은 useState 를 사용한 예시이다.

import React, { useState } from "react";

const Say = () => {
  const [msg, setMsg] = useState("");
  const onClickEnter = () => setMsg("안녕하세요!");
  const onClickLeave = () => setMsg("안녕히 가세요!");

  return (
    <div>
      <button onClick={onClickEnter}>입장</button>
      <button onClick={onClickLeave}>퇴장</button>
      <h1>{msg}</h1>
    </div>
  );
};

export default Say;

1. 컴포넌트가 처음 렌더링 될 때 : ["", setMsg]. 리액트는 ""을 마지막 값으로 기억한다.

 

2. state가 업데이트된다. : enter 버튼을 클릭하면 setMsg("안녕하세요")(setter함수)가 호출된다. 이 때까지는 msg="" 아직 빈 스트링이다. -> msg에 "안녕하세요"를 세팅하면서 리액트에게 새롭게 반영된 값을 기억하라고 한다.

그러면 또 다른 렌더링이 trigger 되는 것이다.

 

3. 컴포넌트의 두 번 째 렌더링 : 리액트가 setter함수에서 새롭게 변경된 값을 기억한다. (msg="안녕하세요") 따라서 2번째 렌더링에서는 ["안녕하세요", setMsg]를 반환한다.

 

 

3.5. 한 컴포넌트에서 여러 개의 상태값 이용하기 

import React, { useState } from "react";

const Say = () => {
  const [msg, setMsg] = useState<String>("");
  const [color, setColor] = useState<String>("black");

  const onClickEnter = () => setMsg("안녕하세요!");
  const onClickLeave = () => setMsg("안녕히 가세요!");

  return (
    <div>
      <button onClick={onClickEnter}>입장</button>
      <button onClick={onClickLeave}>퇴장</button>
      <h1 style={{ color: `${color}` }}>{msg}</h1>
      <button style={{ color: "red" }} onClick={() => setColor("red")}>
        Red
      </button>
    </div>
  );
};

export default Say;

 

 

이 여러개의 state들의 연관관계가 없다면, 혹은 그~렇게 크지 않다면,일일히 상태값을 설정해주는 것도 괜찮다.

 

그러나 2개의 상태값들이 함께 변경되어야 하는 경우가 자주 발생한다면 (예를 들면 Form 양식 안에서의 input 입력 필드 값들 같은 것..) 단일 상태값에 object형태로 선언해주는 것이 훨씬 깔끔할 수 있다.

 

🙋 useState 호출 자체가 상태 변수에 대한 정보를 가지고 있지는 않는다. 그럼 렌더링할 때 어떤 상태값을 변경해야 되는지 어떻게 알 수 있을까?

→ 리액트에서는 최상위 수준에서 React Hooks를 호출하는 규칙을 준수한다면, Hook은 항상 같은 순서로 호출된다. (by 공식문서: https://react.dev/learn/state-a-components-memory#how-does-react-know-which-state-to-return)

또한 모든 컴포넌트에 대해 state값과 setter함수인 setState를 함께 기억하고 있다. (Array) 그리고 초기 렌더링에서 설정된 초기값도 유지하고 있으면서, useState Hook을 호출할 때마다 리액트가 다음 형태의 변경된 state pair(Array)를 제공하는 것이다.

 

 

3.6. State는 독립적이고 지역적인 값이다.

state는 컴포넌트에 국한된 지역적인 값이다. 그래서 만약 동일한 컴포넌트를 두 번 렌더링하면 완전히 독립적인 state값이 2개가 생기는 꼴이다.

일반적인 변수와의 차이점이 발생하는 부분인데, 일반 변수는 특정 함수의 호출이나 코드의 특정 위치에 연결되어 있는반면, state는 화면의 특정 위치에 연결되어 있다.

즉, state 값은 각 개별 컴포넌트에 국한되어 있다.(State is private to the component.) 두 위치에서 렌더링하면 각 복사본은 고유한 상태를 가진다.

 

 

ㅡ 본 글은 리액트를 다루는 기술 도서와 리액트 공식 문서를 참고하여 작성한 글입니다. ㅡ