ContextApi - 사용법과 주의점

김동규·2022년 11월 11일

React 공부하기

목록 보기
3/10

공식문서를 확인하면서 Context API가 단순히 props drilling을 막기 위해서 사용하는 것이 아니라는 사실을 알게되어 Context API의 사용법과 고려사항을 정리해보려고 한다.

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

context의 주된 용도는 다양한 레벨에 네스팅된 많은 컴포넌트에게 데이터를 전달하는 것입니다. context를 사용하면 컴포넌트를 재사용하기가 어려워지므로 꼭 필요할 때만 쓰세요. 여러 레벨에 걸쳐 props 넘기는 걸 대체하는 데에 context보다 컴포넌트 합성이 더 간단한 해결책일 수도 있습니다.

종단 간 관심사를 공유하는 컴포넌트는 의존성을 가지게 되어 재사용이 어려워진다. 그러므로 하나 내지 소수의 컴포넌트에서 사용하는데 단순히 props drilling을 막기 위해 사용하는 경우에는 컴포넌트 합성이 더 나은 대안이라고 제시하고 있다.

// before
<Page user={user} avatarSize={avatarSize} />
// ... 그 아래에 ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... 그 아래에 ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... 그 아래에 ...
<Link href={user.permalink}>
  <Avatar user={user} size={avatarSize} />
</Link>

// after

function Page(props) {
  const user = props.user;
  const userLink = (
    <Link href={user.permalink}>
      <Avatar user={user} size={props.avatarSize} />
    </Link>
  );
  return <PageLayout userLink={userLink} />;
}

// 이제 이렇게 쓸 수 있습니다.
<Page user={user} avatarSize={avatarSize} />
// ... 그 아래에 ...
<PageLayout userLink={...} />
// ... 그 아래에 ...
<NavigationBar userLink={...} />
// ... 그 아래에 ...
{props.userLink}

Context 사용 예시

카카오 FE 기술 블로그의 Atomic design에 관한 글에서 '자주 재사용하지만 그 때마다 내부의 세세한 디자인 순서가 달라지는 컴포넌트'를 위해 compound component를 소개하고 있다.

예시로 제시된 링크에서 하나의 compound component내에서 state를 공유하기 위해 Context API를 사용하는 모습을 보여준다. 아래의 코드는 그것과 별개로 예시적으로 작성해 본 것이다.


// 다른 예시, Styled component 부분 생략

import React, { createContext, useContext, useEffect, useState } from 'react'
import styled from 'styled-components';

const InfoContext = createContext();

const Info = (props) => {
  const [data, setData] = useState({});
  const InfoProviderValue = { data, setData };
  
  const fetchData = async () => {
    const response = await fetch(`data/product/4453.json`);
    const json = await response.json();
    setData(json);
  }
  
  useEffect(() => {
    fetchData()
      .catch(console.error);
  }, [])

  return (
    <StyledContentWrapper>
      <StyledContents>
        <StyledData>
          <ShoeInfoContext.Provider value={InfoProviderValue}>
            {props.children}
          </ShoeInfoContext.Provider>
        </StyledData>
      </StyledContents>
      <StyledDivider />
    </StyledContentWrapper>
  )
}

const Title = () => {
  const { data } = useContext(ShoeInfoContext)

  console.log(data.brandName)
  
  return (
    <StyledTitleWrapper>
      <StTitleBoldUpperCase>{data.brandName}</StTitleBoldUpperCase>
      <StTitleBold>{data.nameEn}</StTitleBold>
      <StTitleBold>{data.name}</StTitleBold>
    </StyledTitleWrapper>
  )
}

const Data = () => {
  const { data } = useContext(ShoeInfoContext);

  return (
    <div>

    </div>
  )
}

const Comment = () => {
  const { data } = useContext(ShoeInfoContext);

  return (
    <div>

    </div>
  )
}

const Footer = () => {
  const { data } = useContext(ShoeInfoContext);

  return (
    <>
      <div>{data.releaseSiteCount}</div>
      <div>{data.views}</div>
    </>
  )
}

ShoeInfo.Title = ShoeTitle;
ShoeInfo.Data = ShoeData;
ShoeInfo.Comment = ShoeComment;
ShoeInfo.Footer = ShoeFooter;


export default Info;

참고

아토믹 디자인을 활용한 디자인 시스템 도입기
React Hooks: Compound Components

profile
공식문서를 사랑하는 프론트엔드 주니어 개발자

0개의 댓글