
컴포넌트에서 context를 읽고 구독할 수 있게 해주는 리액트 훅이다.
const value = useContext(SomeContext);
// 매개변수 SomeContext : 이전에 createContext로 생성한 context
// return : 호출하는 컴포넌트에 대한 context 값을 반환한다. context가 변경되면 context를 읽는 컴포넌트를 리렌더링한다.
import { useContext } from 'react';
function MyComponent() {
// 컴포넌트 최상위 레벨에서 useContext를 이용해 context를 읽고 구독한다.
const theme = useContext(ThemeContext);
// ...
<Context.Provider>는 반드시 useContext() 호출을 수행하는 컴포넌트의 위에 있어야 합니다.value를 받는 provider부터 시작해서 해당 context를 사용하는 자식들에 대해서까지 전부 자동으로 리렌더링[memo](https://react-ko.dev/reference/react/memo)로 리렌더링을 건너뛰어도 새로운 context 값을 받는 자식들을 막지는 못한다.컴포넌트 최상위 레벨에서 호출한다.
useContext는 전달한 context에 대한 context값을 반환하고 위에서 가장 가까운 context Provider를 찾는다.
context를 Button에 전달하려면, 해당 버튼이나 상위 컴포넌트에 해당 context Provider로 감싸줘야 한다.
import { useContext } from 'react';
function Button() {
const theme = useContext(ThemeContext);
// ...
}
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}
function Form() {
// ... renders buttons inside ...
// Form 내부의 Button이 useContext(ThemeContext)를 호출하면
// "dark"를 값으로 받는다.
return (
<Panel title="Welcome">
<Button>Sign up</Button>
<Button>Log in</Button>
</Panel>
);
}
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext(null);
export default function MyApp() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<Form />
<label>
<input
type="checkbox"
checked={theme === 'dark'}
onChange={(e) => {
setTheme(e.target.checked ? 'dark' : 'light')
}}
/>
Use dark mode
</label>
</ThemeContext.Provider>
)
}
function Form({ children }) {
return (
<Panel title="Welcome">
<Button>Sign up</Button>
<Button>Log in</Button>
</Panel>
);
}
function Panel({ title, children }) {
const theme = useContext(ThemeContext);
const className = 'panel-' + theme;
return (
<section className={className}>
<h1>{title}</h1>
{children}
</section>
)
}
function Button({ children }) {
const theme = useContext(ThemeContext);
const className = 'button-' + theme;
return (
<button className={className}>
{children}
</button>
);
}function MyPage() {
const [theme, setTheme] = useState('dark');
return (
//theme을 context value로 provider에 전달
<ThemeContext.Provider value={theme}>
<Form />
<Button onClick={() => {
//전달한 value={theme} 를 업데이트할때는 setTheme을 호출하여 버튼 컴포넌트 리렌더링
setTheme('light');
}}>
Switch to light theme
</Button>
</ThemeContext.Provider>
);
}
트리의 일부분을 다른 값의 Provider로 감싸주면 해당 부분에 대한 context 재정의가 가능하다.
<ThemeContext.Provider value="dark">
...
{/*Footer 안쪽의 버튼은 다른 context값(light)를 받는다.*/}
<ThemeContext.Provider value="light">
<Footer />
</ThemeContext.Provider>
...
</ThemeContext.Provider>
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
function login(response) {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}
return (
<AuthContext.Provider value={{ currentUser, login }}>
<Page />
</AuthContext.Provider>
);
}
import { useCallback, useMemo } from 'react';
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
const login = useCallback((response) => {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}, []);
const contextValue = useMemo(() => ({
currentUser,
login
}), [currentUser, login]);
return (
<AuthContext.Provider value={contextValue}>
<Page />
</AuthContext.Provider>
);
}
MyApp이 리렌더링해야 하는 경우에도 currentUser가 변경되지 않는 한useContext(AuthProvider)를 호출하는 컴포넌트는 리렌더링할 필요가 없다.