-
Notifications
You must be signed in to change notification settings - Fork 4
[학습] Context API를 이해하자!
Jeongsoo Shin edited this page Nov 22, 2019
·
2 revisions
목적
- React component tree에서 global하게 데이터를 공유할 수 있는 방법
- 예컨대 전체 Theme을 하위 컴포넌트들에서 사용한다던지...
- 전역변수를 사용할 수도 있고 / 구독할 수도 있다.
// context를 사용하면 모든 컴포넌트를 일일이 통하지 않고도
// 원하는 값을 컴포넌트 트리 깊숙한 곳까지 보낼 수 있습니다.
// light를 기본값으로 하는 테마 context를 만들어 봅시다.
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Provider를 이용해 하위 트리에 테마 값을 보내줍니다.
// 아무리 깊숙히 있어도, 모든 컴포넌트가 이 값을 읽을 수 있습니다.
// 아래 예시에서는 dark를 현재 선택된 테마 값으로 보내고 있습니다.
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// 이젠 중간에 있는 컴포넌트가 일일이 테마를 넘겨줄 필요가 없습니다.
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// 현재 선택된 테마 값을 읽기 위해 contextType을 지정합니다.
// React는 가장 가까이 있는 테마 Provider를 찾아 그 값을 사용할 것입니다.
// 이 예시에서 현재 선택된 테마는 dark입니다.
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
React.createContext
-
Context 객체를 구독하고 있는 컴포넌트를 렌더링할 때, React는 트리 상위에서 가장 가까이 있는 짝이 맞는 Provider로부터 현재값을 읽음
-
defaultValue 매개변수는 트리 안에서 적절한 Provider를 찾지 못햇을 때에만 쓰이는 값
→ 컴포넌트를 독립적으로 테스트할 때 유용
-
Provider를 통해 undefined을 값으로 보낸다고 해도 구독 컴포넌트들이 defaultValue 를 읽지는 않는다
React.useContext
- render props를 사용하는 것보다 훨씬 편함
- 사용방법
- [Context정의] createContext로 context객체 생성
// StayContext.js
import React, { createContext } from 'react';
const StayContext = createContext();
2. [Context정의] context객체의 Provider를 이용해서 props.children을 렌더링하는 provider역할 객체 생성
→ render props를 사용할 때와 달리, Consumer는 export하지 않아도 된다.
// StayContext.js
function StayProvider(props) {
const value = {
...
};
const { children } = props;
return (
<StayContext.Provider value={value}>
{children}
</StayContext.Provider>
);
}
export { StayContext, StayProvider }
3. [context 제공범위설정] context를 사용할 범위를 Provider로 감싸준다.
// 최상단 컴포넌트 App.js에서 설정한 경우
function App() {
return (
<ThemeProvider theme={theme}>
<OpacityProvider>
<StayProvider>
<GlobalStyle />
<FilterBar />
<StayContainer />
</StayProvider>
</OpacityProvider>
</ThemeProvider>
);
}
4. [context 사용] context를 불러와 value에서 필요한 객체를 불러와 사용한다.
// PriceModal.js
import React, { useContext } from 'react';
import { StayContext } from '../Context/StayContext';
function PriceModal() {
const { addFilter } = useContext(StayContext);
return (
<button onClick={() => { addFilter(); } />
);
}
[ContextObjectName].Provider
<MyContext.Provider value={/* 어떤 값 */}>
-
Context 오브젝트에 포함된 React 컴포넌트인 Provider
→ context를 구독하는 컴포넌트들에게 context의 변화를 알리는 역할
-
Provider 하위에 또 다른 Provider를 배치할 경우, 하위의 값이 우선
-
객체를 value로 보내는 경우 필요없는 렌더링이 생길 수 있다.
→ state를 부모로 끌어올려 해결하라!
Provider 하위에서 context를 구독하는 모든 컴포넌트는, Provider의 value prop이 바뀔 때마다 다시 렌더링됩니다.
대안~합성
- 컴포넌트에 다른 컴포넌트를 담는게 Context API를 사용하는 것보다 훨씬 좋을 수 있다.
- Page에 userLink를 정의하고 자식 컴포넌트들에 props로 전달한다
- 필요할 때 props에서 조회해서 사용한다
- 제어의 역전!
function Page(props) {
const user = props.user;
const userLink = (
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
);
return <PageLayout userLink={userLink} />;
}
// 이제 이렇게 쓸 수 있습니다.
<Page user={user} avatarSize={avatarSize} />
// ... 그 아래에 ...
<PageLayout userLink={...} />
// ... 그 아래에 ...
<NavigationBar userLink={...} />
// ... 그 아래에 ...
{props.userLink}
- pros.children
- 상위 컴포넌트에서 하위 컴포넌트 내에 다른 element를 삽입하여 렌더링하는 경우
- 하위 컴포넌트에서 props.children를 이용하여 그의 하위 컴포넌트에 또 전달할 수 있다.
- 어떤 자식 엘리먼트가 들어올 지 예상할 수 없을 때 사용!