React 공식문서 이해하기 (18)

Syoee·2023년 11월 27일
0

React

목록 보기
18/30
post-thumbnail

Chapter 3. Managing State

#3 컴포넌트 간의 state 공유

학습 목차

1. 예제로 알아보는 state 끌어올리기
2. 각 state의 단일 진실 공급원(SSOT)


1. 예제로 알아보는 state 끌어올리기

  • 이 예제에서는 부모 컴포넌트인 Accordion 컴포넌트가 두 개의 Panel 컴포넌트를 렌더링합니다.

  • Accordion

    • Panel
    • Panel
  • Panel 컴포넌트는 콘텐츠 표시 여부를 결정하는 불리언 타입 isActive state를 가진다.

import { useState } from 'react';

function Panel({ title, children }) {
  const [isActive, setIsActive] = useState(false);
  return (
    <section className="panel">
      <h3>{title}</h3>
      {isActive ? (
        <p>{children}</p>
      ) : (
        <button onClick={() => setIsActive(true)}>
          Show
        </button>
      )}
    </section>
  );
}

export default function Accordion() {
  return (
    <>
      <h2>Almaty, Kazakhstan</h2>
      <Panel title="About">
        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
      </Panel>
      <Panel title="Etymology">
        The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
      </Panel>
    </>
  );
}
  • 한 패널의 버튼을 눌러도 다른 패널에 영향을 주지 않고 독립적으로 동작한다.

  • 그러나 이제 한 번에 하나의 패널만 열리도록 변경하려고 한다.
    설계에 따르면, 두 번째 패널을 열기 위해선 첫 번째 패널을 닫아야 한다. 어떻게 해야 할까?

  • 이 두 패널을 조정하려면 세 단계에 걸쳐 부모 컴포넌트로 “state를 끌어올려야” 한다.

    1. 자식 컴포넌트에서 state를 제거한다.
    2. 공통 부모 컴포넌트에 하드 코딩된 데이터를 전달한다.
    3. 공통 부모 컴포넌트에 state를 추가하고 이벤트 핸들러와 함께 전달한다.
  • 이렇게 하면 Accordion 컴포넌트가 두 Panel 컴포넌트를 조정하고 한 번에 하나씩만 열리도록 할 수 있다.

1-1. 자식 컴포넌트에서 state 제거

  • 부모 컴포넌트에 PanelisActive를 제어할 수 있는 권한을 부여한다.
    즉, 부모 컴포넌트가 isActivePanel에 prop으로 대신 전달하게 된다.
    먼저 Panel 컴포넌트에서 다음 줄을 제거해보자.

const [isActive, setIsActive] = useState(false);

  • 대신 Panel의 props 목록에 isActive를 추가하자.

function Panel({ title, children, isActive }) {

  • 이제 Panel의 부모 컴포넌트는 isActive를 prop으로 전달하여 제어할 수 있다.
    반대로, 이제 Panel 컴포넌트는 isActive 값을 제어할 수 없다.
    이는 이제부터 부모 컴포넌트에 달려 있다.

1-2. 공통 부모에 하드 코딩된 데이터 전달하기

  • state를 끌어올리려면 조정하려는 두 자식 컴포넌트의 가장 가까운 공통 부모 컴포넌트를 찾아야 합니다:

  • Accordion (가장 가까운 공통 부모)

    • Panel
    • Panel
  • 예제에서 가장 가까운 공통 부모는 Accordion 컴포넌트이다.
    두 패널 위에 있고 props를 제어할 수 있으므로 현재 어떤 패널이 활성화되어 있는지에 대한 “진실 공급원(source of truth)”이 된다.
    Accordion 컴포넌트가 두 패널 모두에 하드 코딩된 isActive 값(예: true)을 전달하도록 한다.

import { useState } from 'react';

export default function Accordion() {
  return (
    <>
      <h2>Almaty, Kazakhstan</h2>
      <Panel title="About" isActive={true}>
        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
      </Panel>
      <Panel title="Etymology" isActive={true}>
        The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
      </Panel>
    </>
  );
}

function Panel({ title, children, isActive }) {
  return (
    <section className="panel">
      <h3>{title}</h3>
      {isActive ? (
        <p>{children}</p>
      ) : (
        <button onClick={() => setIsActive(true)}>
          Show
        </button>
      )}
    </section>
  );
}

1-3. 공통 부모에 state 추가

  • state를 끌어올리면 state로 저장하는 항목의 특성이 변경되는 경우가 많다.
    이 경우 한 번에 하나의 패널만 활성화되어야 한다.
    즉, 공통 부모 컴포넌트인 Accordion는 어떤 패널이 활성화된 패널인지 추적해야한다.
    boolean 값 대신, 활성화된 Panel 의 인덱스를 나타내는 숫자를 state 변수로 사용할 수 있다.

const [activeIndex, setActiveIndex] = useState(0);

  • activeIndex0 이면 첫번째 패널이 활성화된 것이고, 1 이면 두 번째 패널이 활성화된 것이다.
  • Panel에서 “Show” 버튼을 클릭하면 Accordian의 활성화된 인덱스를 변경해야 힌다.
  • activeIndex state가 Accordian 내부에 정의되어 있기 때문에 Panel은 값을 직접 설정할 수 없다.
  • Accordion 컴포넌트는 이벤트 핸들러를 prop으로 전달하여 Panel 컴포넌트가 state를 변경할 수 있도록 명시적으로 허용해야 한다.
<>
  <Panel
    isActive={activeIndex === 0}
    onShow={() => setActiveIndex(0)}
  >
    ...
  </Panel>
  <Panel
    isActive={activeIndex === 1}
    onShow={() => setActiveIndex(1)}
  >
    ...
  </Panel>
</>
  • 이제 Panel 안에 있는 <button>은 클릭 이벤트 핸들러로 onShow prop을 사용할 수 있다.
import { useState } from 'react';

export default function Accordion() {
  const [activeIndex, setActiveIndex] = useState(0);
  return (
    <>
      <h2>Almaty, Kazakhstan</h2>
      <Panel
        title="About"
        isActive={activeIndex === 0}
        onShow={() => setActiveIndex(0)}
      >
        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
      </Panel>
      <Panel
        title="Etymology"
        isActive={activeIndex === 1}
        onShow={() => setActiveIndex(1)}
      >
        The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
      </Panel>
    </>
  );
}

function Panel({
  title,
  children,
  isActive,
  onShow
}) {
  return (
    <section className="panel">
      <h3>{title}</h3>
      {isActive ? (
        <p>{children}</p>
      ) : (
        <button onClick={onShow}>
          Show
        </button>
      )}
    </section>
  );
}
  • 이제 state 끌어올리기가 완성되었다.
  • state를 공통 부모 컴포넌트로 옮기면 두 패널을 조정할 수 있게 된다.
    두 개의 “is shown” 플래그 대신 활성화된 인덱스를 사용하면 한번에 하나의 패널만 활성화되게 할 수 있었다.
    그리고 이벤트 핸들러를 자식에게 전달하면 자식이 부모의 state를 변경할 수 있었다.

2. 각 state의 단일 진실 공급원(SSOT)

  • React 애플리케이션(이하 앱)에서 많은 컴포넌트는 고유한 state를 가지고 있다.
    일부 state는 입력값과 같이 leaf 컴포넌트(트리의 맨 아래에 있는 컴포넌트)에 가깝게 “위치” 할 수 있다.
  • 다른 state는 앱의 상단에 더 가깝게 “위치” 할 수 있다.
    예를 들어, 클라이언트 측 라우팅 라이브러리도 일반적으로 현재 경로를 React state에 저장하고 props를 통해 전달하는 방식으로 구현된다.
  • 각 고유한 state들에 대해 해당 state를 “소유”하는 컴포넌트를 선택하게 된다.
    이 원칙은 ”단일 진실 공급원“이라고도 한다.
    이는 모든 state가 한 곳에 있다는 뜻이 아니라, 각 state마다 해당 정보를 소유하는 특정 컴포넌트가 있다는 뜻이다.
    컴포넌트 간에 공유하는 state를 복제하는 대신 공통으로 공유하는 부모로 끌어올려서 필요한 자식에게 전달한다.
  • 앱은 작업하면서 계속 변경된다.
    각 state의 “위치”를 파악하는 동안 state를 아래로 이동하거나 백업하는 것이 일반적이다.
  • 몇 가지 컴포넌트를 사용해 실제로 어떤 느낌인지 알아보려면 React로 사고하기를 읽어보자.

요약

  • 두 컴포넌트를 조정하려면 해당 컴포넌트의 state를 공통 부모로 이동한다.
  • 그런 다음 공통 부모로부터 props를 통해 정보를 전달한다.
  • 마지막으로 이벤트 핸들러를 전달하여 자식이 부모의 state를 변경할 수 있도록 한다.
  • 컴포넌트를 (props에 의해) “제어”할 지 (state에 의해) “비제어”할지 고려해보는 것은 유용하다.

후기

  • 이번 챕터에서는 예시가 많아, 해당 포스트을 읽을 시 이해하기 힘들 수 있을 것 같다는 생각을 했다.
  • 더 다양한 방법으로 표현을 구사하는 방법을 학습해야겠다.

React 공식 문서

https://react.dev/

React 비공식 번역 문서

https://react-ko.dev/

MDN

https://developer.mozilla.org/ko/

Wikipedia

https://ko.wikipedia.org/wiki/

profile
함께 일하고 싶어지는 동료, 프론트엔드 개발자입니다.

0개의 댓글

관련 채용 정보