본문 바로가기
카테고리 없음

React | State가 무엇일까? (State: A Component's Memory)

by 룰루리랄라리 2021. 12. 3.

State: A Component's Memory

컴포넌트는 상호 작용의 결과로 화면에 표시되는 내용을 변경해야 하는 경우가 많습니다.
예를 들면 폼에 입력하면 입력 필드가 업데이트되고, "다음"을 클릭하면 표시되는 이미지가 변경되고, "구매"를 클릭하면 제품을 장바구니에 넣어야 합니다.

컴포넌트는 이런 현재 입력 값, 현재 이미지, 장바구니 등을 "기억"해야 합니다.
React에서는 이러한 종류의 컴포넌트별 메모리를 state라고 합니다.

When a regular variable isn’t enough

handleClick() 이벤트 핸들러가 지역 변수인 인덱스를 업데이트하고 있습니다.

그러나 다음 두 가지 사항으로 인해 지역변수가 업데이트된 사항이 표시되지 않습니다.

  1. 지역 변수는 렌더링 간에 유지되지 않습니다.
    React는 이 구성 요소를 두 번째로 렌더링할 때 처음부터 다시 렌더링합니다.
    로컬 변수에 대한 변경 사항은 렌더링할 때마다 리셋됩니다.
  2. 지역 변수를 변경해도 렌더가 트리거되지 않습니다.
    React는 새 데이터로 구성 요소를 렌더링해야 한다는 것을 인식하지 못합니다.

새 데이터로 구성 요소를 업데이트하려면 두 가지 일이 발생해야 합니다.

  1. 렌더 간에 데이터를 유지합니다.
  2. React를 트리거하여 새 데이터로 구성 요소를 렌더링합니다.

useState Hook은 다음 두 가지를 제공합니다.

  1. 렌더링 간에 데이터를 유지하기 위한 state 변수입니다.
  2. 변수를 업데이트하고 구성 요소를 다시 렌더링하도록 React를 트리거하는 state 설정 함수입니다.

state 변수를 추가하는 방법 (Adding a state variable)

  1. useState를 사용하여 상태유지를 하려면 하래 코드를 추가해야합니다.
    import { useState } from 'react';
  2. index를 초기화 하는 코드를 useState를 이용한 방법으로 변경합니다.
    const [index, setIndex] = useState(0);
    index는 상태 변수이고 setIndex는 setter 함수입니다.
    [] 는 배열분해이고 배열에서 각각의 값을 읽을 수 있습니다.
    useState가 반환하는 배열은 항상 2개의 항목이 있습니다.
  3. handleClick함수에 setState를 이용하여 state 변수를 변경해줍니다.
    function handleClick() { setIndex(index + 1); }
import { useState } from 'react';
import { sculptureList } from './data.js';

export default function Gallery() {
  const [index, setIndex] = useState(0);

  function handleClick() {
    setIndex(index + 1);
  }

  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleClick}>
        Next
      </button>
      <h2>
        <i>{sculpture.name} </i> 
        by {sculpture.artist}
      </h2>
      <h3>  
        ({index + 1} of {sculptureList.length})
      </h3>
      <img 
        src={sculpture.url} 
        alt={sculpture.alt}
      />
      <p>
        {sculpture.description}
      </p>
    </>
  );
}

 

첫번째로 배우는 Hook (Meet your first Hook)

React에서는 use로 시작하는 다른 모든 함수를 Hook 이라고 합니다.
Hook은 React가 렌더링 되는 동안 사용할 수 있는 특별한 함수입니다.

 

Hooks(ex.useHook)는 컴포넌트 또는 자체 Hooks의 최상위 컴포넌트에서만 호출할 수 있습니다.
또한 조건, 루프 또는 기타 중첩 함수 내에서 Hooks를 호출할 수 없습니다.
Hooks는 함수이지만 구성 요소의 요구 사항에 대한 무조건 선언으로 생각하면 도움이 됩니다.
파일 상단에서 모듈을 "import"하는 것과 유사하게 구성요소 상단에서 React 기능을 "use"합니다.

 

Anatomy of useState

useState를 호출하면 이 컴포넌트가 무언가를 기억하기를 원한다고 React에 알리는 것입니다.

아래의 코드는 index를 기억하길 원한다고 React에 알리는 코드입니다.

const [index, setIndex] = useState(0);

 

useState의 유인한 인수는 state변수의 초기값입니다.
컴포넌트가 렌더링될 때마다 useState는 index,setIndex가 포함된 배열을 제공합니다.


index는 저장한 값이 있는 상태 변수입니다.
setIndex는 state setter function 으로 state 변수가 업데이트 하고 다시 컴포넌트를 렌더링하도록 하는 트리거입니다.

 

Giving a component multiple state variables

하나의 컴포넌트에서 많은 유형의 state 변수를 가질 수 있습니다.

 

이 때 state가 서로 관계가 없는 경우라면 따로 state 변수를 선언하는 것이 좋습니다.
그러나 state변수를 관계가 있고, 함께 변경하는 이벤트가 많다면 이 state변수들은 하나로 결합하여 선언하는 것이 좋을 수 있습니다.

 

예를 들어, 만약 많은 필드가 있는 폼이라면, 필드 1개당 state 변수를 갖는 것보다 해당 개체를 포함하는 한개의 state 변수를 갖는 것이 더 편리합니다.

 

 

?) React가 어떤 state를 return 할지 알 수 있을까
Hooks는 간결한 구문을 사용하기 위해 동일한 컴포넌트의 모든 렌더링을 할 떄 호출 순서에 의존합니다.
위의 규칙("최상위 수준에서 Hook만 호출")을 따르면 Hook이 항상 동일한 순서로 호출되기 때문에 이것은 실제로 잘 작동합니다.
또한 linter 플러그인(코딩 스타일과 에러를 체크해주는 플러그인)은 대부분의 실수를 포착합니다.

 

내부적으로 React는 모든 컴포넌트에 대한 상태 쌍의 배열을 보유합니다.
또한 렌더링 전에 선언된 초기값으로 설정된 현재 쌍 인덱스를 유지합니다.
useState를 호출할 때마다 React는 다음 상태 쌍을 제공하고 인덱스를 증가시킵니다.

 

State is isolated and private

state는 화면의 컴포넌트 인스턴스에 local입니다.
즉, 동일한 컴포넌트를 두 번 렌더링하면 각 복사본(인스턴스)은 완전히 격리된 상태가 됩니다!
둘 중 하나를 변경해도 다른 하나는 영향을 받지 않습니다.

서로 분리되어 있는 상태는 일반 변수(모듈 상단에서 선언할 수 있는)와 state를 다르게 만듭니다.


state는 특정 함수 호출이나 코드의 위치에 연결되지 않지만 화면의 특정 위치에 "로컬"입니다.
두 개의 컴포넌트를 렌더링했으므로 해당 상태가 별도로 저장됩니다.

 

또한, 상위 컴포넌트가 하위 컴포넌트들의 state가 있는지 여부는 "모릅니다".
props와 달리 state는 이를 선언하는 컴포넌트에 대해 완전히 비공개입니다.
상위 컴포넌트는 하위 컴포넌트의 state를 변경할 수 없습니다.

이를 통해 나머지 구성 요소에 영향을 주지 않고 컴포넌트에 상태를 추가하거나 제거할 수 있습니다.

 

Page는 상위 컴포넌트
Gallery는 하위 컴포넌트

import Gallery from './Gallery.js';

export default function Page() {
  return (
    <div className="Page">
      <Gallery />
      <Gallery />
    </div>
  );
}

댓글