처음 만난 리액트 문서


14.3 Context를 사용하기 전에 고려할 점

Context는 다른 레벨의 많은 컴포넌트들이 특정 데이터를 필요로 하는 경우에 주로 사용합니다. 하지만 무조건 Context를 사용하는 것이 좋은 것은 아닙니다. 왜냐하면 컴포넌트와 Context가 연동이 되면, 재사용성이 떨어지기 때문입니다. 그래서 다른 레벨의 많은 컴포넌트들이 데이터를 필요로 하는 경우가 아니라면 기존에 사용하던 방식대로 props를 통해 데이터를 전달하는 컴포넌트 Composition방법이 더 적합하다고 할 수 있습니다. 아래 예시 코드를 한 번 보도록 하겠습니다.

// Page컴포넌트는 PageLayout컴포넌트를 렌더링
<Page user={user} avatarSize={avatarSize} />

// PageLayout컴포넌트는 NavigationBar컴포넌트를 렌더링
<PageLayout user={user} avatarSize={avatarSize} />

// NavigationBar컴포넌트는 Link컴포넌트를 렌더링
<NavigationBar user={user} avatarSize={avatarSize} />

// Link컴포넌트는 Avatar컴포넌트를 렌더링
<Link href={user.permalink}>
    <Avatar user={user} size={avatarSize} />
</Link>

위 코드에는 사용자 정보와 아바타 사이즈를 몇 단계에 걸쳐서 하위 컴포넌트인 LinkAvatar로 전달하는 Page컴포넌트가 있습니다. 여기에서 가장 하위 레벨에 위치한 Avatar컴포넌트가 useravatarSize를 필요로 하기 때문에, 그걸 위해서 여러 단계에 걸쳐서 props를 통해 useravatarSize를 전달해주고 있습니다. 하지만 이 과정은 굉장히 불필요하게 느껴집니다. 또한 Avatar컴포넌트에 추가적인 데이터가 필요해지면, 해당 데이터도 추가로 여러 단계에 걸쳐서 넘겨주어야 하기 때문에 굉장히 번거롭습니다.

여기서 Context를 사용하지 않고 이러한 문제를 해결할 수 있는 한 가지 방법은 Avatar컴포넌트를 변수에 저장하여 직접 넘겨주는 것입니다. 앞서 9장에서 배운 element variable형태로 말이죠. 그렇게 하면 중간 단계에 있는 컴포넌트들은 useravatarSize에 대해 전혀 몰라도 됩니다. 아래 코드를 한 번 보도록 하겠습니다.

function Page(props) {
    const user = props.user;

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

    // Page컴포넌트는 PageLayout컴포넌트를 렌더링
    // 이 때 props로 userLink를 함께 전달함.
    return <PageLayout userLink={userLink} />;
}

// PageLayout컴포넌트는 NavigationBar컴포넌트를 렌더링
<PageLayout userLink={...} />

// NavigationBar컴포넌트는 props로 전달받은 userLink element를 리턴
<NavigationBar userLink={...} />

위 코드에서는 useravatarSizeprops로 들어간 Avatar컴포넌트를 userLink라는 변수에 저장한 뒤에, 해당 변수를 하위 컴포넌트로 넘기고 있습니다. 이렇게 하면 가장 상위 레벨에 있는 Page컴포넌트만 Avatar컴포넌트에서 필요로 하는 useravatarSize에 대해 알고 있으면 됩니다.

이런 방식은 중간 레벨의 컴포넌트들을 통해 전달해야 하는 props를 없애고 코드를 더욱 간결하게 만들어 줍니다. 또한 최상위에 있는 컴포넌트에 조금 더 많은 권한을 부여해줍니다. 하지만 모든 상황에 이 방식이 좋은 것은 아닙니다. 데이터가 많아질수록 상위 컴포넌트에 몰리기 때문에 상위 컴포넌트는 점점 더 복잡해지고, 하위 컴포넌트들은 너무 유연해지게 됩니다. 위에서 사용한 방법을 조금 더 응용해서 하위 컴포넌트들을 여러 개의 변수로 나눠서 전달할 수도 있습니다. 아래 코드를 한 번 보도록 하겠습니다.

function Page(props) {
    const user = props.user;
    
    const topBar = (
        <NavigationBar>
            <Link href={user.permalink}>
                <Avatar user={user} size={props.avatarSize} />
            </Link>
        </NavigationBar>
    );
    const content = <Feed user={user} />;

    return (
        <PageLayout
            topBar={topBar}
            content={content}
        />
    );
}

이 방식은 하위 컴포넌트의 의존성을 상위 컴포넌트와 분리할 필요가 있는 대부분의 경우에 적합한 방법입니다. 또한 렌더링 전에 하위 컴포넌트가 상위 컴포넌트와 통신해야 하는 경우 render props를 사용하여 처리할 수도 있습니다.

하지만 어떤 경우에는 하나의 데이터에 다양한 레벨에 있는 중첩된 컴포넌트들이 접근할 필요가 있을 수 있습니다. 이러한 경우에는 위 방식은 사용할 수가 없고, Context를 사용해야 합니다. Context는 해당 데이터와 데이터의 변경사항을 모두 하위 컴포넌트들에게 broadcast(널리 알리는 것) 해주기 때문입니다. Context를 사용하는 것이 적합한 데이터의 대표적인 예로는 현재 지역정보(locale), UI 테마, 그리고 캐싱된 데이터 등이 있습니다.


마지막 업데이트: 2025년 08월 21일 09시 05분

이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.

On this page