githubEdit

Context를 사용해 데이터를 깊게 전달하기

  • React에서는 일반적으로 부모 컴포넌트가 자식 컴포넌트로 props를 통해 데이터를 전달함.

  • 하지만, 중간에 많은 컴포넌트를 거쳐야 하거나, 여러 컴포넌트에서 동일한 데이터를 필요로 하면 props 전달이 번거로움.

  • Context API를 사용하면 부모 컴포넌트가 트리 아래의 모든 컴포넌트에 props 없이도 데이터를 제공 가능.

  • 이를 통해 props drilling 문제를 해결하고, 코드의 가독성과 유지보수성을 높일 수 있음.

Props 전달하기의 문제점

Props 전달하기arrow-up-right는 UI 트리를 통해 해당 데이터를 사용하는 컴포넌트에 명시적으로 데이터를 전달하는 훌륭한 방법입니다.

Prop Drilling 문제점

  • 특정 prop을 트리를 통해 깊이 전달해야 하는 경우, 코드가 장황하고 불편해짐.

  • 여러 컴포넌트에서 같은 prop이 필요하면, 이를 관리하는 공통 조상이 트리 상단에 위치할 가능성이 높음.

  • 이런 구조에서는 state를 과도하게 상위 컴포넌트로 끌어올려야 하는데, 이를 **“Prop Drilling”**이라고 함.

image (28)

props를 사용하지 않고 데이터를 사용할 트리의 내부 컴포넌트로 순간이동 시킬 방법은? → Context

Context: Props 전달하기의 대안

아래 코드를 한 번 봐봅시다

import Heading from './Heading.js';
import Section from './Section.js';

export default function Page() {
  return (
    <Section> // level = 1
      <Heading level={1}>Title</Heading>
      <Section> // 2
        <Heading level={2}>Heading</Heading>
        <Heading level={2}>Heading</Heading>
        <Heading level={2}>Heading</Heading>
        <Section> // 3
          <Heading level={3}>Sub-heading</Heading>
          <Heading level={3}>Sub-heading</Heading>
          <Heading level={3}>Sub-heading</Heading>
        </Section>
      </Section>
    </Section>
  );
}

Heading 태그 안에 중복적으로 level props를 넘겨주고 있는데, 아래와 같이 표현할 수 있으면 좋겠죠 ?

하지만 어떻게 Heading 컴포넌트가 Section의 level을 알 수 있을까요 ?

그렇게 하려면 자식에게 트리 위 어딘가에 있는 데이터를 요청해야 합니다.

이럴때 Context를 사용할 수 있습니다 !

Context 사용 3단계

  1. Context 생성

  2. 데이터가 필요한 컴포넌트에서 context 사용

  3. 데이터를 지정하는 컴포넌트에서 context 제공

image (29)

Context 실습하기

  1. context를 만들어야 합니다.

    컴포넌트에서 사용할 수 있도록 파일에서 내보내야 합니다.

  1. Context 사용하기

    React에서 useContext 훅과 생성한 Context를 가져옵니다.

    useContext는 Hook으로 useState, useReducer과 같이 Hook은 React 컴포넌트의 안에서만 호출 가능합니다.

  2. Context 제공하기

    Section 컴포넌트는 자식들을 렌더링하고 있습니다.

    LevelContext를 자식들에게 제공하기 위해 context provider로 감싸줍니다.

  • 이것은 React에게 Section 내의 어떤 컴포넌트가 LevelContext를 요구하면 level을 주라고 알려줍니다.

  • 컴포넌트는 그 위에 있는 UI 트리에서 가장 가까운 <LevelContext.Provider>의 값을 사용합니다.

기존 코드와 동일한 결과이지만 level prop을 각 Heading 컴포넌트에 전달할 필요는 없습니다! 대신 위의 가장 가까운 Section에게 제목 레벨을 “확인”합니다.

같은 컴포넌트에서 context를 사용하며 제공하기

지금은 각각의 섹션에 level을 수동으로 지정해야 합니다.

Context를 통해 위의 컴포넌트에서 정보를 읽을 수 있으므로 각 Section은 위의 Section에서 level을 읽고 자동으로 level + 1을 아래로 전달할 수 있습니다.

Context로 중간 컴포넌트 지나치기

Context를 제공하는 컴포넌트와 context를 사용하는 컴포넌트 사이에 원하는 만큼의 컴포넌트를 삽입할 수 있습니다.

image (30)

Section 컴포넌트의 역할

  • Section 컴포넌트는 Context를 통해 계층 정보를 관리하므로, props를 따로 전달하지 않아도 됩니다.

  • 즉, 어디에서든 을 사용하면 적절한 크기로 자동 조정됩니다.

Context를 활용한 컴포넌트의 자동 적응

  • Context를 사용하면 컴포넌트가 렌더링되는 위치에 따라 자동으로 변화할 수 있습니다.

  • 이는 마치 CSS의 속성 상속과 비슷한 방식으로 동작합니다.

Context는 CSS 속성 상속과 유사함

  • CSS에서에 color: blue;를 지정하면, 자식 요소는 자동으로 파란색을 사용합니다.

  • 하지만 중간에 color: green;이 지정되면 그 이후의 자식 요소는 초록색이 됩니다.

  • React의 Context도 마찬가지로, 부모에서 지정한 Context는 자식에게 전달됩니다.

  • 하지만 중간에서 새로운 Provider를 감싸면 값이 재정의됩니다.

서로 다른 Context는 독립적으로 동작

  • CSS에서 color와 background-color는 서로 영향을 주지 않습니다.

  • 즉, color를 빨간색으로 바꿔도 background-color는 그대로 유지됩니다.

  • React에서도 각 Context는 독립적으로 동작합니다.

  • createContext()로 만든 각각의 Context는 완전히 분리되며, 서로 간섭하지 않습니다.

  • 따라서 하나의 컴포넌트가 여러 개의 Context를 사용하더라도 문제없이 동작합니다.

Context를 사용하기 전에 고려할 것

다음은 context를 사용하기 전 고려해볼 몇 가지 대안들입니다.

  1. props로 전달하기

    • 사소한 컴포넌트들이 아니라면 여러 개의 props가 여러 컴포넌트를 거쳐 가는 것은 그리 이상한 일이 아닙니다.

    • 데이터의 흐름이 props를 통해 분명해져 코드를 유지보수 하기에도 좋습니다.

  2. 컴포넌트를 추출하고 JSX를 children으로 전달하기.arrow-up-right

    • 데이터를 사용하지 않는 많은 중간 컴포넌트 층을 통해 어떤 데이터를 전달하는 경우에는 컴포넌트를 추출하는 것을 잊은 경우가 많습니다.

만약 이 접근 방법들이 잘 맞지 않는다면 context를 고려해보세요.

Context 사용 예시

  • 테마 지정하기

    사용자가 모양을 변경할 수 있는 애플리케이션의 경우에 (ex. 다크 모드) context provider를 앱 최상단에 두고 시각적으로 조정이 필요한 컴포넌트에서 context를 사용할 수 있습니다.

  • 현재 계정

    로그인한 사용자를 알아야 하는 컴포넌트가 많을 수 있습니다. Context에 놓으면 트리 어디에서나 편하게 알아낼 수 있습니다.

    일부 애플리케이션에서는 동시에 여러 계정을 운영할 수도 있습니다. (e.g. 다른 사용자로 댓글을 남기는 경우.) 이런 경우에는 UI의 일부를 서로 다른 현재 계정 값을 가진 provider로 감싸 주는 것이 편리합니다.

  • 라우팅

    대부분의 라우팅 솔루션은 현재 경로를 유지하기 위해 내부적으로 context를 사용합니다. 이것이 모든 링크의 활성화 여부를 “알 수 있는” 방법입니다. 라우터를 만든다면 같은 방식으로 하고 싶을 것입니다.

  • 상태 관리

    애플리케이션이 커지면 결국 앱 상단에 수많은 state가 생기게 됩니다. 아래 멀리 떨어진 많은 컴포넌트가 그 값을 변경하고 싶어할 수 있습니다.

    흔히 reducer를 context와 함께 사용하는 것arrow-up-right은 복잡한 state를 관리하고 번거로운 작업 없이 멀리 있는 컴포넌트까지 값을 전달하는 방법입니다.

Last updated