보통의 경우 부모 컴포넌트에서 자식 컴포넌트로 Props를 통해 데이터를 전달한다.
근데 중간에 많은 컴포넌트를 거쳐야 하거나, 응용프로그램에서 많은 컴포넌트에서 동일한 정보들이 필요한 경우에는 props를 전달하는것이 번거롭고 불편할 수 있다.
Context
를 사용하면 명시적으로 props를 전달해주지 않아도 부모 컴포넌트가 트리에 있는 어떤 자식 컴포넌트에(부모로부터 얼마나 멀리 떨어져 있던지 간에 상관없음)나 데이터를 사용할 수 있다.
props를 전달하는것 또한 훌륭한 방법이나 어떠한 prop을 트리를 통해 깊이 전해줘야 하거나, 많은 컴포넌트에서 같은 prop이 필요한 경우에 장황하고 불편할 수 있다.
데이터가 필요한 여러 컴포넌트의 가장 가까운 공통 조상은 트리상 높이 위치할 수 있고, 그렇게 높게까지 state를 끌어 올리는것은 prop drilling이라는 상황을 초래할 수 있다.
동시에 props만으로는 가장 가까운 부모 컴포넌트의 레벨(depth)을 알 수 없다.
props를 사용하면 부모 컴포넌트의 레벨을 알 수 없기에, context가 활약할 수 있게되고, 아래와 같은 3단계로 진행된다.
Context는 부모가 트리 내부 전체에, 심지어 멀리 떨어진 컴포넌트에조차 어떤 데이터를 제공할 수 있도록 한다.
컴포넌트에서 사용할 수 있도록 파일에서 내보낼 context를 만들어야 한다.
또 createContext
의 유일한 인자는 default value다.
// LevelContext.js
import { createContext } from 'react';
export const LevelContext = createContext(1);
useContext
훅과 위에서 생성한 Context를 import
import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';
Heading 컴포넌트의 props로 받고있던 level값을 useContext를 사용해 값을 읽도록 수정
// Before
export default function Heading({ level, children }) {
// ...
}
// After
export default function Heading({ children }) {
const level = useContext(LevelContext);
// ...
}
일단 useContext또한 훅이기 때문에 컴포넌트 상단에서 호출할 수 있고, useContext는 React에게 Heading 컴포넌트가 LevelContext를 읽으려 한다고 알려준다.
Section 컴포넌트에서 children을 렌더링하고 있는데,
1단계에서 생성한 LevelContext를 children에게 제공하기 위해서 context provider로 감싸준다.
// Before
export default function Section({ children }) {
return (
<section className="section">
{children}
</section>
);
}
// After
import { LevelContext } from './LevelContext.js';
export default function Section({ level, children }) {
return (
<section className="section">
<LevelContext.Provider value={level}>
{children}
</LevelContext.Provider>
</section>
);
}
context를 사용하면 prop을 각각의 Heading 컴포넌트에 전달할 필요가 없어지고, 대신 위의 가장 가까운 Section 컴포넌트에서 level을 확인한다.
동시에 Level Context를 읽으면서 컴포넌트 스스로 트리 구조에서 얼마나 깊이 있는지 확인할 수 있다. (이건 좀 신기한듯)
Context는 컴포넌트가 트리 상 아래에 위치한 모든 곳에 데이터를 제공하도록 합니다.
Context를 전달하려면 다음과 같습니다
1.export const MyContext = createContext(defaultValue)로 context를 생성하고 내보내세요.
2. useContext(MyContext) Hook에 전달해 얼마나 깊이 있든 자식 컴포넌트가 읽을 수 있도록 합니다.
3. 자식을 <MyContext.Provider value={...}>로 감싸 부모로부터 context를 받도록 합니다.
Context는 중간의 어떤 컴포넌트도 지나갈 수 있습니다.
Context를 활용해 “주변에 적응하는” 컴포넌트를 작성할 수 있습니다.
Context를 사용하기 전에 props를 전달하거나 JSX를 children으로 전달하는 것을 먼저 시도해보세요.