컴포넌트간에 상태 공유하기

파이리·2023년 7월 27일

React

목록 보기
6/9
post-thumbnail

원문 : https://react.dev/learn/sharing-state-between-components


두 컴포넌트의 상태가 항상 함께 변경되길 원한다면, 두 컴포넌트에서 상태를 제거하고 가장 가까운 공통 부모로 이동한 다음 props를 통해 전달하면 됩니다.

이를 lifting state up이라고 하며 리액트 코드에서 가장 흔히 사용되는 방법 중 하나입니다.

Lifting state up by example

이 예제에는 별도의 Panel 컴포넌트와 공통의 부모 Accordion을 가지고 있습니다. 각 Panel 컴포넌트는 isActive 라는 boolean 값을 갖는 상태를 가지고 있습니다. 이 상태는 컨탠츠를 보이게할지 결정합니다.

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>
    </>
  );
}
  • PanelShow 버튼을 클릭할 경우 컨텐츠가 보여집니다.

  • Panel에서 버튼을 클릭할 경우 다른 Panel에는 어떠한 영향도 끼치지 않습니다.

  • 따라서 현재 Panel 컴포넌트는 독립적입니다.

    하지만, 원하는 것은 한번에 하나의 Panel이 컨텐츠를 보여주도록 하는 것이라 가정하겠습니다. 이를 구현하기 위해서는 세 단계를 거쳐 부모 컴포넌트로 상태를 끌러올려야 합니다.

  1. 자식 컴포넌트에서 상태를 제거합니다.
  2. 공통 부모에서 데이터를 전달합니다.
  3. 공통 부모에서 상태를 추가하고 이벤트 핸들러와 함께 전달합니다.

자식 컴포넌트에서 상태 제거하기

부모 컴포넌트에서 PanelisActive 상태를 제어할 수 있도록 합니다. 즉, 부모 컴포넌트에서 isAcitveprops를 통해 Panel에게 전달하도록 변경하면 됩니다.

// 자식 컴포넌트에서 상태 제거
const [isActive, setIsActive] = useState(false);
// isActive를 props로 전달
function Panel({ title, children, isActive }) {

부모 컴포넌트에서 하드코딩한 데이터 전달하기

상태를 올리려면 두 Panel 컴포넌트에서 가장 가까운 공통 부모 컴포넌트를 찾아야 합니다. 이 예시에서는 Accordion 컴포넌트입니다. Accordion 컴포넌트는 어떤 Panel이 활성화되어 있는지에 대해 정확히 알 수 있습니다.

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>
  );
}

공통 부모 컴포넌트에서 상태 추가

상태를 끌어올리면 상태에서 보관하는 항목의 특성이 변경되는 경우가 많습니다.

이 경우에서는 한 번에 하나의 패널만 활성화해야 합니다. 즉, Accordion이 어떤 패널이 활성화되었는지 알아야합니다. 따라서 Boolean 값 대신 숫자를 상태로 변수로 지정하여 어떤 패널이 활성되었는지 인덱스로 구별할 수 있습니다.

const [activeIndex, setActiveIndex] = useState(0);
<>
  <Panel
    isActive={activeIndex === 0}
    onShow={() => setActiveIndex(0)}
  >
    ...
  </Panel>
  <Panel
    isActive={activeIndex === 1}
    onShow={() => setActiveIndex(1)}
  >
    ...
  </Panel>
</>

이것으로 lifting state up이 완료되었습니다. 상태를 공통의 상위 컴포넌트로 이동시키면서 두 Panel를 동시에 조정할 수 있었습니다. 그리고 이벤트 핸들러를 자식에게 전달함으로서 자식이 부모의 상태를 변경할 수 있게 하였습니다.

각 상태에 대한 단일 진실 소스 ( A single source of truth for each state)

React 어플리케이션에서는 많은 컴포넌트가 고유한 state를 가지고 있습니다. 일부 stateinput 요소들 같은 리프 컴포넌트에 가깝게 live 할 수 있습니다. 다른 상태는 앱의 상단에 더 가깝게 live할 수 있습니다. 예를 들어 클라이언트 측 라우팅 라이브러리는 일반적으로 현재 경로를 React state에 저장하고 props를 통해 전달하는 방식으로 구현됩니다.

각각의 고유한 state에 대해 이를 소유할 컴포넌트를 선택합니다. 이 원칙을 '단일 소스 ( single source )'를 갖는다고도 합니다. 모든 상태가 한 곳에 존재하다는 것이 아니라 각 상태마다 해당 정보를ㄹ 보유하는 특정 컴포넌트가 있다는 뜻입니다. 컴포넌트 간에 공유 상태를 복제하는 대신 공통의 부모 컴포넌트로 상태를 올려서 필요한 자식 컴포넌트에게 전달합니다.

profile
프론트엔드 개발자

0개의 댓글