React에서 Props와 State는 부모 컴포넌트와 자식 컴포넌트 또는 한 컴포넌트 안에서 데이터를 다루기 위해 사용된다. 이 Props와 State를 사용하게 되면 부모 컴포넌트에서 자식 컴포넌트, 즉, 위에서 아래, 한쪽으로 아래와 같이 데이터가 흐르게 된다.
만약 다른 컴포넌트에서 한쪽으로 흐르고 있는 데이터를 사용하고 싶은 경우, React에서 데이터는 위에서 아래로 흐르게 되므로 사용하고 싶은 데이터와 이 데이터를 사용할 컴포넌트의 공통 부모 컴포넌트에 State를 만들고 사용하고자 하는 데이터를 Props를 전달하면 된다.
하지만 이처럼 컴포넌트 사이에 공유되는 데이터를 위해 매번 공통 부모 컴포넌트를 수정하고 하위 모든 컴포넌트에 데이터를 Props로 전달하는 것은 매우 비효율적이다.
이와 같은 문제를 해결하기 위해 React에서는 Flux라는 개념을 도입하였고 그에 걸맞은 Context를 제공하기 시작했다.
Context는 부모 컴포넌트로부터 자식 컴포넌트로 전달되는 데이터의 흐름과는 상관없이 전역적인 데이터를 다룰 때 사용한다. 전역 데이터를 Context에 저장한 후, 데이터가 필요한 컴포넌트에서 해당 데이터를 아래와 같이 불러와 사용할 수 있다.
React에서 Context를 사용하기 위해서는 Context API를 사용해야 하며, Context의 Provider와 Consumer를 사용해야 한다.
Context에 저장된 데이터를 사용하기 위해서는 공통 부모 컴포넌트에 Context의 Provider를 사용하여 데이터를 제공해야 하며, 데이터를 사용하려는 컴포넌트에서 Context의 Consumer를 사용하여 실제로 데이터를 사용한다.
Context는 createContext 라는 함수를 통해 만들 수 있다.
import { createContext } from 'react';
const LocaleContext = createContext();
참고로 이때 아래처럼 기본값을 넣어줄 수도 있다.
import { createContext } from 'react';
const LocaleContext = createContext('ko');
Context를 쓸 때는 반드시 값을 공유할 범위를 정하고 써야 하는데,
이때 범위는 Context 객체에 있는 Provider 라는 컴포넌트로 정해줄 수 있다.
이때 Provider의 value prop으로 공유할 값을 내려주면 된다.
import { createContext } from 'react';
const LocaleContext = createContext('ko');
function App() {
return (
<div>
... 바깥의 컴포넌트에서는 LocaleContext 사용불가
<LocaleContext.Provider value="en">
... Provider 안의 컴포넌트에서는 LocaleContext 사용가능
</LocaleContext.Provider>
</div>
);
}
useContext 라는 Hook을 사용하면 값을 가져와 사용할 수 있다.
이때 아규먼트로는 사용할 Context를 넘겨주면 된다.
import { createContext, useContext } from 'react';
const LocaleContext = createContext('ko');
function Board() {
const locale = useContext(LocaleContext);
return <div>언어: {locale}</div>;
}
function App() {
return (
<div>
<LocaleContext.Provider value="en">
<Board />
</LocaleContext.Provider>
</div>
);
}
Provider 역할을 하는 컴포넌트를 하나 만들고,
여기서 State를 만들어서 value 로 넘겨줄 수 있다.
그리고 아래의 useLocale 같이
useContext 를 사용해서 값을 가져오는 커스텀 Hook을 만들 수도 있다.
이렇게 하면 Context에서 사용하는 State 값은
반드시 우리가 만든 함수를 통해서만 쓸 수 있기 때문에
안전한 코드를 작성하는데 도움이 된다.
import { createContext, useContext, useState } from 'react';
const LocaleContext = createContext({});
export function LocaleProvider({ children }) {
const [locale, setLocale] = useState();
return (
<LocaleContext.Provider value={{ locale, setLocale }}>
{children}
</LocaleContext.Provider>
);
}
export function useLocale() {
const context = useContext(LocaleContext);
if (!context) {
throw new Error('반드시 LocaleProvider 안에서 사용해야 한다');
}
const { locale } = context;
return locale;
}
export function useSetLocale() {
const context = useContext(LocaleContext);
if (!context) {
throw new Error('반드시 LocaleProvider 안에서 사용해야 한다');
}
const { setLocale } = context;
return setLocale;
}