Context로 Props Drilling 없이 컴포넌트에 값 전달하기
context란?
일반적으로 부모 컴포넌트에서 자식 컴포넌트로 props를 통해 데이터를 전달한다. 하지만 중간에 props를 사용하지 않는 여러 컴포넌트를 거쳐야하는 경우 코드가 장황해질 수 있다.
context를 사용하면 부모 컴포넌트가 props를 통해 전달하지 않고도 그 아래 트리의 모든 컴포넌트에서 데이터를 사용할 수 있다.
context 만들기
createContext의 인수는 기본값이다. 기본값으로는 모든 종류의 값(객체 포함)을 전달할 수 있다. 기본값은 UI 트리상 위에 Provider가 없으면 사용된다.
import { createContext } from "react";
export const LevelContext = createContext(1);
useContext
는 컴포넌트에서 context를 읽고 구독할 수 있게 해준다. 인수로 방금 생성한 context를 전달하면 호출하는 컴포넌트에 대한 context 값을 반환한다. 이 값은 호출한 컴포넌트에서 UI 트리상 위에 있는 가장 가까운 Provider에 전달된 value이다. 반환된 값은 항상 최신 값이며 리액트는 context가 변경되면(Object.is로 비교) context를 읽는 컴포넌트를 자동으로 리렌더링한다.
import { useContext } from "react";
import { LevelContext } from "./LevelContext.js";
const level = useContext(LevelContext);
Provider로 감싸 LevelContext를 제공한다. 여기서 value는 Provider 내부에 이 컨텍스트를 읽는 모든 컴포넌트에 전달하려는 값이다. Provider 내부에서 useContext(SomeContext)를 호출하는 컴포넌트는 UI 트리에서 가장 가까운 컨텍스트 Provider의 value를 받는다.
import { LevelContext } from "./LevelContext.js";
export default function Section({ level, children }) {
return (
<section className="section">
<LevelContext.Provider value={level}>{children}</LevelContext.Provider>
</section>
);
}
context를 사용하면 가장 가까운 컴포넌트에서 컨텍스트 Provider의 value를 읽을 수 있으므로 각 Section은 위의 Section에서 level을 읽고 level에 수를 더해 아래로 전달할 수 있다.
import { useContext } from "react";
import { LevelContext } from "./LevelContext.js";
export default function Section({ children }) {
const level = useContext(LevelContext);
return (
<section className="section">
<LevelContext.Provider value={level + 1}>{children}</LevelContext.Provider>
</section>
);
}
이렇게 Context를 사용하면 “주변 환경에 적응”하고 렌더링되는 위치 (context)에 따라 다르게 표시되는 컴포넌트를 만들 수 있다.
🚫 주의 🚫
context는 state가 자주 바뀌는 경우(1초에도 여러 번 바뀌는 경우)에는 최적화되어있지 않기 때문에 적합하지 않다. 이 경우에는 리덕스를 사용하는 것이 좋다.
정리
- context를 사용하면 props를 통해 전달하지 않아도 Provider로 감싼 모든 컴포넌트에서 데이터를 사용할 수 있다.
- context는 createContext를 사용해 생성하며 이때 인수는 기본값이다. 기본값은 UI 트리상 위에 Provider가 없으면 사용된다.
- Provider로 컴포넌트를 감싸면 하위 컴포넌트들에 value로 지정한 값을 전달할 수 있다.
- useContext는 context에 접근할 수 있게 해주며, 이 값은 호출한 컴포넌트 기준으로 UI 트리상 위에서 가장 가까운 Provider에 전달된 value이다.
- 리액트는 Object.is로 비교하여 context의 변경을 감지하면 context를 읽는 모든 컴포넌트를 리렌더링시킨다.
참고
리액트 공식문서
- React