컴포넌트 사이에 State 공유하기

박재현·2024년 3월 5일
0

Nomadcoder React Study 4기

목록 보기
23/49

때때로 두 컴포넌트의 state가 항상 함께 변경되기를 원할 수 있는데, 그렇게 하려면 각 컴포넌트에서 state를 제거하고 가장 가까운 공통의 부모 컴포넌트로 옮긴 후 props로 전달을 해야한다.

이 방법을 State 끌어올리기 라고 하며 React 코드를 작성할때 가장 흔히 하는 일 중 하나다. (한글로 하니까 이상해 보이는데, 영어로 말하면 lifting state up 이라고 함)


예제

예시로 부모 컴포넌트인 Accordion이 두개의 Panel을 랜더링 한다고 하자.

  • Accordion
    - Panel
    - Panel

Panel 컴퍼논트는 콘텐츠 표시 여부를 결정하는 Boolean 타입의 isActive 상태를 가진다고 하자.

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가 lifting up 되어야 한다!

  1. 자식 컴포넌트의 state를 제거
  2. 하드 코딩된 값을 공통의 부모로부터 전달
  3. 공통 부모 컴포넌트에 state를 추가하고 이벤트 핸들러와 함께 전달

Step 1

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

Panel 컴포넌트에서 isActive state를 제거한 다음, 가장 가까운 공통 부모 컴포넌트에서 컨트롤 할 수 있도록 하자.

동시에 Panel Props에 isActive를 추가하자.
(부모로부터 isActive 상태를 받아올 수 있어야 하니까)

Step 2

부모인 Accordion 컴포넌트 내부에서 2개의 Panel 컴포넌트에 isActive props를 내려준다. (일단은 true로 내려주도록 하자)

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

Step3

공통부모인 Accordion에 아래와 같이 두개의 자식 컴포넌트에서 참조할 state를 추가한다.

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

그 다음, 자식 컴포넌트인 Panel에서 state를 변경할 수 있도록 이벤트 핸들러를 넘겨주어야 하는데,

자식인 Panel 컴포넌트에서 부모 컴포넌트의 state를 변경할 이벤트핸들러 함수를 받을 수 있도록 props에 onShow를 추가한다.

요약

  • Panel 자식 컴포넌트
    부모 컴포넌트의 state를 변경할 이벤트 핸들러를 props로 전달받도록 props에 onShow를 추가
  • Accordion 부모 컴포넌트
    서로다른 2개의 자식 컴포넌트에서 참조할 state를 만들어두고, state값과 state값을 변경할 setter를 poprs로 넘겨주자

궁극적으로 첫번째 Panel은 state가 0일때 show되고, 2번째 Panel은 state가 1이될때 show된다.

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


참고

profile
기술만 좋은 S급이 아니라, 태도가 좋은 A급이 되자

0개의 댓글

관련 채용 정보