context로 받아온 데이터를 쉽게 받아볼 수 있게 도와주는 역할을 함
리액트로 만든 앱은 여러 개의 컴포넌트 들로 이루어져 있음
최상위 앱에서 시작해서 트리형태로 뻗어나감
부모 컴포넌트 -> 자식 컴포넌트로 Props를 통해 전달됨
// App
<Header user={user} />
// Header
<SearchBar user={user} />
이렇게 부모컴포넌트가 자식컴포넌트의 태그에 하나하나 props를 넣어서 단계별로 전달을 해줘야함
앱 내부에서 많은 컴포넌트들이 공통적으로 필요한 전역적인 데이터가 존재할 수 있음(Global Data)
현재 로그인된 사용자 정보, 테마, 언어 등
전역적인 데이터를 단계별로 전달해야한다면 비효율적임 -> Context API 사용
Context는 앱 안에서 전역적으로 사용되는 데이터들을 여러 컴포넌트들 끼리 쉽게 공유할 수 있는 방법을 제공해줌
해당 데이터를 갖고 있는 상위 컴포넌트가 "데이터 필요한 사람!"하고 하위 컴포넌트들에게 방송을 해주면 하위 컴포넌트들은 트리 어디에 위치해있든 상관없이 "나 그 데이터 쓸래"라고만 해주면 해당 값에 접근 가능
사용자 정보, 테마, 앱에서 사용된 언어와 같은 수많은 컴포넌트들이 필요한 전역적 데이터를 전달하기에 굉장히 편리함
Props Drilling
만약 최하위 컴포넌트인 C와 E에 필요한 데이터를 전달하려면 Props를 통해 모든 중간 컴포넌트들을 거쳐서 단계별로 전달해야 함
문제점: 가장 아래의 C와 E 컴포넌트만 데이터가 필요함에도 불구하고 데이터는 전달과정에서 모든 컴포넌트들을 거쳐가야 함
-> 컴포넌트들이 받는 props 많아짐, 코드 길어짐, 오류 발생시 부모 컴포넌트들을 다 확인해봐야 함
Context를 사용하면 컴포넌트를 재사용하기 어려워 질 수 있음
Context의 주요 목적은 다양한 레벨의 많은 컴포넌트들에게 전역적인 데이터를 전달하기 위함임
props drillig을 피하기 위한 목적이라면 Component Composition(컴포넌트 합성)을 먼저 고려해보자
Component Composition(컴포넌트 합성)이란?
function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
function CardTitle({ title }) {
return <h2>{title}</h2>;
}
function CardContent({ content }) {
return <p>{content}</p>;
}
// 이제 이 컴포넌트들을 합성해봅시다
function MyCard() {
return (
<Card>
<CardTitle title="안녕하세요!" />
<CardContent content="이것은 카드 내용입니다." />
</Card>
);
}
여기에서 Card는 부모 컴포넌트이고, CardContent는 자식 컴포넌트임
이들을 MyCard에서 조합해서 하나의 완성된 카드를 만들었음
CardTitle과 CardContent를 다른 곳에서도 쉽게 사용 가능 -> 재사용성
카드의 내용을 쉽게 변경 가능 -> 유연성
장점
children prop이란?
<Card>
<CardTitle title="제목" />
<CardContent content="내용" />
</Card>
여기에서 < CardTitle >과 < CardContent >가 Card 컴포넌트의 Childern임
즉, 빵, 치즈, 햄이 있다고 하면 빵(Card 컴포넌트), 치즈(CardTitle 컴포넌트), 햄(CardContent)이 됨
이 재료(컴포넌트)를 조합해서 완성된 샌드위치가 MyCard임
장점
실제 코드 구현
UseContext.js
Page.jsx
Content.jsx
Footer.jsx
Header.jsx
Page.jsx
UseContext.js의 isDark를 보면 앱의 전체적인 테마에 대한 정보를 담고 있기 때문에 전역적 데이터라고 볼 수 있음
앱 규모가 크다면 수많은 컴포넌트들이 isDark를 필요로 할 것임
플로우를 보면 UseContext 컴포넌트가 Page 컴포넌트에게 isDark를 props로 넘겨줌 -> Page 컴포넌트는 isDark를 받아오지만 실제적으로 사용하고 있지 않음(단지 자식 컴포넌트에게 전달하기 위해 받아옴) = isDark를 필요로 하지 않는 중간 컴포넌트임 -> 비효율적임
Context를 사용해서 중간 컴포넌트없이 데이터가 필요한 컴포넌트들에게 공유해보자
UseContext.js에서 ThemeContext import 하기
Page 컴포넌트를 ThemeContext.Provider로 감싸주기
Header.jsx
Content.jsx
Footer.jsx
최종 화면
만약 useContext로 ThemeContext에 대한 정보를 받아왔는데 상위에서 Context의 Provider로 감싸주지 않았다면(value가 없는 상태라면) ThemeContext에서 인자로 넘겨준 초기값을 받아오게 됨
방금 만듬 앱은 value를 사용해서 값을 넘겨주기 때문에 초기값이 필요하지 않음
실제 코드 구현 2
상위 컴포넌트에 import해주기(UseContext.js)
가장 상위에 Provider로 감싸주기