리액트로 만든 앱은 여러개의 컴포넌트로 이루어져 있다.
최상위 App 컴포넌트로 시작해서 트리 형태로 뻗어나간다.
부모 컴포넌트에서 자식 컴포넌트로 props가 전달이되는데, 이 props를 전달할 때는 부모 컴포넌트에서 자식 컴포넌트로 단계별로 전달해주어야 한다.
컴포넌트가 많지만 공통적으로 필요한 data 정보가 있다고 가정했을 때 (유저 정보라던가, 테마 등) 이런 전역 데이터를 프롭스로 전달해야 한다면, 부모 -> 자식 -> 자식의자식 -> 자식의자식의자식 .. 형태로 필요한 컴포넌트들에게 계속해서 props로 내려 보내주어야 해서 상당히 귀찮고 복잡해진다.
이러한 문제를 해결할 수 있는 방법으로 Context
가 있다.
컨텍스트는 앱 안에서 전역적으로 사용되는 데이터들을 여러 컴포넌트가 쉽게 공유할 수 있는 방법을 제공해준다.
프롭스로 데이터를 하나씩 내려보내주지 않아도 하위 컴포넌트에서 필요하다면 해당 데이터 값에 접근할 수 있다.
컨텍스트를 사용하면 여러 컴포넌트가 사용해야 하는 전역적인 데이터를 사용할 때 편리하다.
자식의 자식의 자식 컴포넌트인 3번 컴포넌트만 데이터를 필요로 함에도 불구하고 실질적인 데이터는 App 컴포넌트에 있기 때문에 불필요하게 1번과 2번 컴포넌트가 프롭스를 받아서 저 아래에 있는 3번 컴포넌트까지 넘겨주어야 한다.
컴포넌트가 필요하지 않은 프롭스를 전달 받아야하는 과정에서 잘못 전달할 수도 있고 에러발생시 프롭스를 전달하고 있는 컴포넌트마다 찾아가서 찾아야 할 수도 있다.
위에서 확인한 것처럼 불필요한 과정 제거, 오류를 덜기 위한 방법으로 Context를 사용할 수 있다.
App에만 여러 컴포넌트가 사용할 수 있는 데이터를 가지고 있고, 이 App에 있는 데이터가 필요한 컴포넌트에 useContext
훅을 사용해서 해당 데이터를 받아올 수 있도록 할 수 있다.
그렇다면, props를 굳이 사용할 필요가 없다고 느낄 수도 있을 것이다.
하지만, Context를 사용하면 컴포넌트를 재사용하기 어려울 수 있으므로 꼭 필요한 경우에만 context를 사용하는 것이 좋다.
props가 불필요하게 여러번 보내져야 할 때 (Prop drilling)라면 Component Composition(컴포넌트 합성)을 먼저 고려해보는 것이 좋다.
Prop drilling 이란
데이터를 필요로 하는 멀리 있는 컴포넌트에게 여러번에 걸쳐 props로 전달하는 것을 의미하는 용어이다.
1-1. useContext export 방법1
context 폴더에 작명.js
파일을 만든 후 createContext를 import하고 createContext로 return 받은 변수를 export 해준다.
/* MyContext.js */
import { createContext } from 'react';
export const MyContext = createContext(null);
1-2. useContext export 방법2
1-1
번 방법으로 해도 되지만 React.CreateContext
를 호출해서 반환 값을 담은 변수를 export 해주는 방법으로 사용할 수도 있다.
export const MyContext = React.createContext();
/* App.js */
import { MyContext } from '파일경로';
컴포넌트명.Provider
로 태그를 만들어 준 후 value 속성 안에 전달할 데이터를 작성해준다./* App.js */
return (
<MyContext.Provider value={{전달할 데이터1, 전달할 데이터2}}>
// 데이터를 공유할 컴포넌트 코드는 여기에
</MyContext.Provider>
)
이제 value로 집어넣은 데이터를 props를 사용하지 않고도 접근할 수 있게 된다.
이제 MyContext.Provider로 감싸진 컴포넌트들은 value로 보낸 데이터들을 공유해서 사용할 수 있게 된다.
/* context의 data를 사용할 컴포넌트 위치 */
import { MyContext } from '위치 경로';
사용할 때는 컨텍스트를 import 해와야 한다.
const 프롭스대신컨텍스트 = useContext(MyContext);
useContext(컨텍스트이름);
을 사용해서 변수에 저장해보고 출력하든 확인해보면 이전에 value 속성으로 보낸 데이터들을 확인할 수 있다.
디스트럭처링 문법을 사용해서 꺼내와도 된다.
이제 import 해서 가져왔기 때문에 이 컨텍스트 데이터가 필요한 곳에서 props나 일반 state변수 사용할 때와 동일하게 사용할 수 있게 된다.
Context API는 컴포넌트가 여러개 중첩될 때 사용하면 편리하지만, state가 변경됐을 때 다른 컴포넌트도 재렌더링돼서 성능 이슈가 있을 수 있다.
또, 컨텍스트 사용시 컴포넌트 재사용이 어려울 수도 있다.
참고 자료
React Hooks에 취한다 - useContext + Context API | 리액트 훅스 시리즈
A better way of solving prop drilling in React apps
리액트 공식문서 Context