컴포넌트 합성을 통해 트리 구조가 복잡해질수록 하위 컴포넌트로 props를 전달하기 위해 drilling이 발생할 수 있게되고, 이때 유지보수 및 코드 읽기가 어려워지는 문제가 있다.
context는 React 컴포넌트 트리 안에 전역적으로 데이터를 공유할 수 있도록 고안된 방법으로 context를 사용하면 중간 엘리먼트들에게 prop를 넘겨주지 않아도 되고, 유지보수도 수월해진다.
단, 컴포넌트 재사용에 어려움이 생긴다는 문제가 있기 때문에 필요할 때만 사용한다.
다크 모드 설정 - context를 사용하지 않는 예제
const { useState } = React;
function Header ({isDark}) {
return (
<header
className="header"
style={
{backgroundColor : isDark ? 'black' : 'lightgray',
color : isDark ? 'white' : 'black'}
}
>
<h1>welcome to Greedy World</h1>
</header>
);
}
function Content ({ isDark }) {
return (
<div
className="content"
style={
{backgroundColor : isDark ? 'black' : 'white',
color : isDark ? 'white' : 'black'}
}
>
<h1>컨텐츠 영역입니다.</h1>
</div>
);
}
function Footer ({ isDark, setIsDark }) {
const toggleHandler = () => setIsDark(!isDark);
return (
<footer
className="footer"
style={
{backgroundColor : isDark ? 'black' : 'lightgray',
color : isDark ? 'white' : 'black'}
}
>
<button onClick={ toggleHandler }>{isDark ? 'Light Mode' : 'Dark Mode'}</button>
Copyright 2023. team-greedy. allrights reserved.
</footer>
);
}
function Page ({ isDark, setIsDark }) {
return (
<div className="page">
<Header isDark={isDark}/>
<Content isDark={isDark}/>
<Footer isDark={isDark} setIsDark={setIsDark}/>
</div>
);
}
function App () {
const [isDark, setIsDark] = useState(false);
return <Page isDark={isDark} setIsDark={setIsDark}/>;
}
context 객체 생성(createContext) 인자로 defaultValue 전달, defaultValue가 없는 경우 null 설정 context 객체를 구독하고 있는 컴포넌트를 랜더링할 때 React는 트리 상위에 가장 가까이 있는 Provider로부터 현재 값을 읽어들인다.
이때 적절한 Provider를 찾지 못할 때 쓰이는 값이 defaultValue이다.
다크 모드 설정 - useContext를 사용한 예제
const { useState, createContext, useContext } = React; //createContext가 필요하다
const DarkModeContext = createContext(null); //DarkModeContext로 createContext 생성
function Header () {
const DarkModeContext = useContext(DarkModeContext);
const { isDark } = context;
return (
<header
className="header"
style={
{backgroundColor : isDark ? 'black' : 'lightgray',
color : isDark ? 'white' : 'black'}
}
>
<h1>welcome to Greedy World</h1>
</header>
);
}
function Content () {
const DarkModeContext = useContext(DarkModeContext);
const { isDark } = context;
return (
<div
className="content"
style={
{backgroundColor : isDark ? 'black' : 'white',
color : isDark ? 'white' : 'black'}
}
>
<h1>컨텐츠 영역입니다.</h1>
</div>
);
}
function Footer () {
const DarkModeContext = useContext(DarkModeContext);
const { isDark, setIsDark } = context;
const toggleHandler = () => setIsDark(!isDark);
return (
<footer
className="footer"
style={
{backgroundColor : isDark ? 'black' : 'lightgray',
color : isDark ? 'white' : 'black'}
}
>
<button onClick={ toggleHandler }>{isDark ? 'Light Mode' : 'Dark Mode'}</button>
Copyright 2023. team-greedy. allrights reserved.
</footer>
);
}
function Page () {
return (
<div className="page">
<Header/>
<Content/>
<Footer/>
</div>
);
}
Provider
는 context를 구독하고 있는 컴포넌트들에게 context의 변화를 알리는 역할을 한다. Provider는 value prop을 이용하여 하위 컴포넌트에게 값을 전달한다. 이때 값을 받을 수 있는 컴포넌트 수에는 제한이 없다.
prop 하위에서 context를 구독하는 모든 컴포넌트는 value prop이 바뀔 때마다 다시 랜더링된다.
App작성
function App () {
const [isDark, setIsDark] = useState(false);
return (
<DarkModeContext.Provider value={ { isDark, setIsDark }}>
<Page/>
</DarkModeContext.Provider>
);
}