지난 글에서 Props의 역할이 컴포넌트의 속성을 정의하기 위한 것이며, 우리가 많이 사용하는 '하향 데이터 통신' 기능은 결과적으로 속성을 전달하는 과정에서 활용할 수는 있지만, 속성을 전달하는 과정이 하향식으로 이뤄지다보니 그런 식으로도 활용할 수 있게 되는 것이며, 속성의 본연적 기능은 자식 컴포넌트의 정체를 정의하는 것으로 보아야 정확하게 사용할 수 있을 것임을 살펴보았다. 그렇다면 실제로 컴포넌트 간의 통신을 할 때에는 무엇을 사용해야 할까? 여러가지 방법이 있지만, 이번에 다뤄볼 Context API가 그 중 하나가 될 수 있다.
API(Application Programming Interface)는 그 용어 자체적으로도 연결의 의미를 지니고 있다. 즉 접면(Interface)으로써 둘 사이를 연결하는 역할을 하는데, 서버와 서버, 또는 서버와 클라이언트 등 연결점이 없는 둘 사이를 연결해주는 역할을 하는 요소를 우리는 API라고 부른다.
ContextAPI 역시 마찬가지로, 이름 자체에서 알 수 있듯이 맥락적(context)으로 응용 절차를 연결하는(API) 역할을 수행하는 것이 ContextAPI이다. 맥락적이라는 말은 세세하고 작은 부분보다는 크고 전반적인 의미를 담고 있는데, ContextAPI는 이렇듯 시스템 전반적인 범위에서의 통신을 담당하는 전역적인(global) API이다.
일반적으로 API가 메신저 역할을 담당한다는 점을 생각해보면 이 ContextAPI 역시도 마찬가지이다. 떨어져 있는 값 또는 기능을 전달하는 배달원의 역할이라고 생각하면 이해하기 쉬운데, ContextAPI는 이러한 배달원의 역할을 하여 컴포넌트 간의 값을 전달하거나 함수를 전달하는 역할을 한다.
이를 사용할 때에는 사용할 컴포넌트에서 아래와 같이 사용할 수 있다.
import { useContext } from 'react';
function Button() {
const theme = useContext(ThemeContext);
// ...
Button이라는 컴포넌트에서 useContext라는 훅을 사용해 ThemeContext라는 컴포넌트에서 받아들인 값을 theme라는 상수에 저장하고 있다. 이 ThemeContext는 Button의 상단에서 아래와 같이 포함하고 있으면 된다.
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}
function Form() {
// <Button></Button>
}
ThemeContext라는 컴포넌트가 .Provider라는 메소드를 행하는 형태로 Button을 포함하는 Form을 감싸고 있는데, 이렇게 되면 ThemeContext를 통해 전달(provide)되는 값이 그 하위의 컴포넌트들에서 레벨에 상관없이 구독 가능해진다. 또한 여러 컴포넌트가 한꺼번에 이를 읽는 것도 가능하다.
function MyPage() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Form />
<Button onClick={() => {
setTheme('light');
}}>
Switch to light theme
</Button>
</ThemeContext.Provider>
);
}
위와 같이 상태(state)와 같이 사용하면 값을 바꾸는 것도 가능한데, 위의 예제는 Button이 클릭되면 setTheme이라는 상태 변화 함수가 수행되어 light라는 테마로 값을 바꿔주는 형태를 구현하고 있다. 이렇듯이 contextAPI는 상향/하향 전반적으로 사용될 수 있으며, Provider가 포함하는 전체 요소와 통신할 수 있다.
<ThemeContext.Provider value="dark">
//...
<ThemeContext.Provider value="light">
<Footer />
</ThemeContext.Provider>
//...
</ThemeContext.Provider>
이 contextAPI Provider는 위와 같이 중첩하여 사용할 수도 있는데, 이렇게 되면 가장 가까운 Provider가 우선권을 갖는다. 위의 예시에서 Footer는 light의 Theme 값을 구독하게 됨을 의미한다.
전달하는 값은 상수만 가능한 것은 아니며, 함수도 가능하다. 예를 들어
function MyApp() {
function login(response) {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}
return (
<AuthContext.Provider value={{ login }}>
<Page />
</AuthContext.Provider>
);
}
위와 같이 사용하면 Page 컴포넌트는 login 함수를 호출하여 사용할 수 있으며, 이를 통해 출력되는 결과를 전달받아 사용할 수 있다.
이 경우, 최적화(리렌더링 발생)는 주의해서 행할 필요가 있다.
'React.Native' 카테고리의 다른 글
[QML] 레이아웃 잡기 : Grid, Row, Column (0) | 2024.11.24 |
---|---|
[React] 무의미한 반복을 피하기 위해 기억하기 : useMemo (1) | 2024.11.19 |
[React] Props는 통신용이 아니다 : Props 진짜 이해하기 (3) | 2024.11.15 |
[React] 값 참조하기: useRef (0) | 2024.11.12 |
[React] useEffect와 정리함수(clean up) (10) | 2024.11.10 |