Context API
React.createContext()
📌 Context (객체) 생성
const MyContext = React.createContext(기본값);
리액트에서 렌더링이 일어날 때, context를 구독하는 하위 컴포넌트가 나오면
현재 context의 값을 가장 가까이에 있는 상위 레벨의 Provider로부터 받아오게 된다.
만약 상위 레벨에 매칭되는 Provider가 없다면 기본값이 사용된다.
기본값은 Provider 없이 컴포넌트를 테스트할 때 유용하며,
기본값으로 undefined를 넣으면 기본값이 사용되지 않는다.
Context.Provider
하위 컴포넌트들이 해당 context의 값을 사용할 수 있도록 전달해 준다. (Provider→제공자)
모든 Context 객체는 Provider라는 리액트 컴포넌트를 갖는다.
Context.Provider 컴포넌트로 하위 컴포넌트들을 감싸주면,
모든 하위 컴포넌트들이 해당 context의 데이터에 접근할 수 있게 된다.
📌 Provider 사용
<MyContext.Provider value={/* 어떤 값 */}>
value prop은 Provider 컴포넌트의 하위 컴포넌트들에게 전달된다.
Provider & Consumer
하위 컴포넌트들은 데이터를 소비한다는 뜻에서, Consumer 컴포넌트라고 부른다.
- 하나의 Provider 컴포넌트는 여러 개의 Consumer 컴포넌트와 연결될 수 있으며,
- 여러 개의 Provider 컴포넌트는 중첩되어 사용될 수 있다.
Consumer 컴포넌트는 context 값의 변화를 지켜보다가, 값이 변경되면 재렌더링된다.
Provider value에서 주의해야 할 사항
Provider 컴포넌트가 재렌더링 될 때마다 모든 하위 Consumer 컴포넌트가 재렌더링 된다.
그래서 Provider의 부모 컴포넌트가 재렌더링 되었을 때, 의도치 않게 Consumer 컴포넌트 또한 재렌더링될 수도 있다.
아래 코드에서 Provider 컴포넌트가 렌더링될 때마다, 모든 Consumer 컴포넌트들을 재렌더링하게 된다.
⏩ value prop의 값(객체)이 매번 새롭게 생성되기 때문이다.
📌 예제1-1.
function App(props) {
return (
<MyContext.Provider value={{something: 'something'}}>
<Toolbar />
</MyContext.Provider>
);
}
✅ value를 직접 넣는 것이 아닌 state로 옮기고, 해당 state의 값을 넣어준다.
📌 예제1-2. 예제1-1 수정 ( state 사용 )
function App(props) {
const [value, setValue ] = useState({something: "something"});
return(
<MyContext.Provider value={value}>
<Toolbar />
</MyContext.Provider>
)
}
state를 사용하여 불필요한 재렌더링을 막을 수 있다.
Class.contextType
Provider 하위에 있는 클래스 컴포넌트에서, context에 접근하기 위해 사용하는 것이다.
해당 API를 사용하면 단 하나의 context만 사용할 수 있다.
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* MyContext의 값을 이용한 코드 */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* ... */
}
}
MyClass.contextType = MyContext;
// MyClass라는 클래스 컴포넌트는 MyContext에 접근할 수 있다.
Context.Consumer
함수 컴포넌트에서 context의 데이터를 구독하는 컴포넌트이다.
📌 Consumer 사용
<MyContext.Consumer>
{value => /* context 값을 이용한 렌더링 */}
</MyContext.Consumer>
컴포넌트의 자식으로 함수가 올 수 있다(function as a child).
자식으로 들어간 함수가 현재 context의 value를 받아서, 리액트 노드로 반환한다.
함수로 전달되는 value는 Provider의 value prop과 동일하다.
만약 상위 컴포넌트에 Provider가 없다면 value는 기본값으로 지정된다. (createContext의)
function as a child
컴포넌트의 자식으로 함수를 사용하는 방법이다.
📌 function as a child 사용하기
//children이라는 prop을 직접 선언하는 방식
<Profile children={name => <p>이름 : {name}</p>} />
// Profile컴포넌트로 감싸서 children으로 만드는 방식
<Profile>{name => <p>이름: {name}</p>}</Profile>
Context.displayName
Context 객체는 displayName 문자열 속성을 설정할 수 있다.
React 개발자 도구는 이 문자열을 사용해서 context를 어떻게 보여줄지 결정한다.
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools
여러 개의 Context 사용하기
여러 개의 context를 동시에 사용하기 위해서는, Context.Provider를 중첩하여 사용한다.
// 기본값이 light인 ThemeContext
const ThemeContext = React.createContext('light');
// 로그인한 유저 정보를 담는 UserContext
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// context 초기값을 제공하는 App 컴포넌트
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// 여러 context의 값을 받는 컴포넌트
function Content() {
return (
<ThemeContext.Consumer>{theme => (
<UserContext.Consumer>{user => (
<ProfilePage user={user} theme={theme} /> )}
</UserContext.Consumer> )}
</ThemeContext.Consumer> );
}
둘 이상의 context 값이 함께 쓰이는 경우가 많다면 그 값들을 한 번에 받는 render prop 컴포넌트를 만드는 것이 좋다.
useContext()
📌 useContext() Hook을 사용한 예시
function MyComponent(props){
const value = useContext(MyContext);
return (
...
)
}
context 객체(React.createContext에서 반환된 값)를 받아 그 context의 현재 값을 반환한다.
context의 현재 값은 컴포넌트 트리 상에서 가장 가까운 상위 Provider 컴포넌트의 value에 의해 결정된다.
만약 context 값이 변경되면, 변경된 값과 함께 useContext Hook을 사용하는 컴포넌트 또한 재렌더링 된다.
useContext로 전달한 인자는 context 객체 그 자체이어야 한다!
- 맞는 사용: useContext(MyContext)
- 틀린 사용: useContext(MyContext.Consumer)
- 틀린 사용: useContext(MyContext.Provider)
🚀 참고
- 처음 만난 리액트(React) , 소플 - 섹션14. Context
- 리액트 공식문서 - Context
- 리액트 공식문서 - useContext()
'React' 카테고리의 다른 글
[React] styled-components 설치 및 사용, 스타일 확장 (0) | 2023.01.12 |
---|---|
[React] Lifting State Up - Shared State (0) | 2023.01.12 |
[React] Context 개념 및 특징 (0) | 2023.01.06 |
[React] Composition VS. Inheritance - Containment, Specialization (0) | 2023.01.06 |
[React] Hook의 규칙과 Custom Hook - 커스텀 훅 특징 및 사용법 (0) | 2022.12.30 |
댓글