단계마다 일일이 props
를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있는 기법입니다.
일반적인 React 어플리케이션에서 데이터는 위에서 아래로 props
를 통해 전달되지만, 여러 컴포넌트들에게 전해줘야 하는 prop
의 경우, 이 과정이 번거로울 수 있습니다.
context
를 이용하면, 트리단계마다 명시적으로 props
를 넘겨주지 않아도 많은 컴포넌트가 이 값을 공유하도록 할 수 있습니다.
context
의 주된 용도는 다양한 레벨의 많은 컴포넌트에게 데이터를 전달하는 것입니다. context
를 사용하면 컴포넌트를 재사용하기 어려워지므로 꼭 필요할 때 쓰세요.
여러 레벨에 걸쳐 props
넘기는 걸 대체하는 데 context보다 컴포넌트 합성이 더 간단한 해결책일 수도 있습니다.
// Link에서 사용하기 위해 'user'와 'avaterSize'가 계속 props로 하위 컴포넌트에 전달되고 있습니다
<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>
function Page(props) {
const user = props.user;
const userLink = (
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
);
return <PageLayout userLink={userLink} />;
}
// 이제 이렇게 쓸 수 있습니다.
// 이제 'user'와 'avatarSize'를 하위 컴포넌트에서 알 필요가 없습니다.
<Page user={user} avatarSize={avatarSize} />
// ... 그 아래에 ...
<PageLayout userLink={...} />
// ... 그 아래에 ...
<NavigationBar userLink={...} />
// ... 그 아래에 ...
{props.userLink}
같은 데이터를 트리 안 여러 레벨이 있는 많은 컴포넌트에게 주어야 할 때가 있습니다. 데이터 값이 변할 때마다 모든 하위 컴포넌트에게 알려줄 필요가 있을 때 context를 사용합니다.
(React 공식문서)
const MyContext = React.createContext(defaultValue);
createContext는 Context 객체를 만듭니다.
Context 객체를 구독하고 있는 컴포넌트를 렌더링할 때 React는 트리 상위에서 가장 가까이 있는 짝이 맞는 Provider로부터 현재 값을 읽습니다.
<MyContext.Provider value={/* 어떤 값 */}>
Provider는 context를 구독하는 컴포넌트들에게 context의 변화를 알리는 역할을 합니다.
Provider 컴포넌트는 value prop을 받아 하위에 있는 컴포넌트에게 전달합니다.
Provider 하위에 또다른 Provider를 배치하는 것도 가능하며, 이 경우 하위 Provider의 값이 우선시 됩니다.
Provider 하위에서 context를 구독하는 모든 컴포넌트는 Provider의 value prop이 바뀔 때마다 다시 렌더링 됩니다.
export function RepeatingProviderPage() {
return (
<FirstProvider>
<SecondProvider>
<ExamplePageComponent />
</SecondProvider>
</FirstProvider>
);
}
<MyContext.Consumer>
{value => /* context 값을 이용한 렌더링 */}
</MyContext.Consumer>
context 변화를 구독하는 React 컴포넌트입니다. 이 컴포넌트를 사용하면 함수 컴포넌트 안에서 context를 구독할 수 있습니다.
이때 Context.Consumer의 자식은 함수여야 합니다.
이 함수가 받는 value
매개변수 값은 해당 context
의 Provider
중, 상위트리에서 가장 가까운 Provider
의 value prop
과 동일합니다.
만약 상위에 Provider
가 없다면 value
매개변수 값은 createContext()
에 보냈던 defaultValue
와 동일합니다.
최근에는 React Hook이 추가되면서 Context.Consumer 대신 useContext를 사용하는 추세입니다.
useContext를 사용하면 Context.Consumer 보다 깔끔하게 Context의 전역데이터에 접근할 수 있습니다.
import React, { useContext } from "react";
import LangContext from "./LangContext";
function Button({ toggleLang }) {
const lang = useContext(LangContext);
return <button onClick={toggleLang}>{lang}</button>;
}
useContext를 호출한 컴포넌트는 context 값이 변경되면 항상 리렌더링 될 것입니다.
컴포넌트를 리렌더링 하는 것에 비용이 많이 든다면, 메모이제이션을 사용하여 최적화할 수 있습니다.
Context 객체는 displayName 문자열 속성을 설정할 수 있습니다.
React 개발자 도구는 이 문자열을 사용해서 context를 어떻게 보여줄 지 결정합니다.
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools