context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다.
상위 컴포넌트에서 데이터를 Set하고 set한 데이터를 하위 컴포넌트에서 get할 수 있어야 한다. context를 사용하려면 데이터를 set하는 과정과 get하는 과정이 필요하다.
모든 하위 컴포넌트가 데이터를 가져올 수 있어야 하므로 데이터를 set하는 곳은 가장 상위 컴포넌트여야 한다.
데이터를 Set하는 순서는,
src 아래에 contexts라는 폴더를 생성하고 PersonContext.jsx 파일을 만든다.
// PersonContext.jsx
import React from 'react';
const PersonContext = React.createContext();
export default PersonContext;
// index.js (가장 상위 컴포넌트)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import PersonContext from './contexts/PersonContext';
const persons = [
{ id: 0, name: 'Mark', age: 38 },
{ id: 1, name: 'Hanna', age: 27 },
];
ReactDOM.render(
<PersonContext.Provider value={persons}>
<App />
</PersonContext.Provider>,
document.getElementById('root'),
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
reportWebVitals();
Context 객체에 포함된 React Component인 Provider는 context를 구독하는 컴포넌트들에게 context의 변화를 알리는 역할을 한다.
Provider 컴포넌트는 value prop을(여기서 persons) 받아서 이 값을 하위에 있는 컴포넌트에게 전달한다. Provider 하위에서 context를 구독하는 모든 컴포넌트는 Provider의 value prop이 바뀔 때마다 다시 렌더링된다.
여기까지 데이터를 Set 하는 과정이었다. 이제 어떻게 데이터를 Get하는지 알아보자.
데이터는 모든 하위 컴포넌트에서 접근 가능하다. 접근 방법에는 세가지가 있다.
src 아래에 component 폴더를 생성하고 Example1.jsx 파일을 만든다.
// Example1.jsx
import React from 'react';
import PersonContext from '../contexts/PersonContext';
const Example1 = () => (
<PersonContext.Consumer>
{value => <ul>{JSON.stringify(value)}</ul>}
</PersonContext.Consumer>
);
export default Example1;
Context.Consumer의 자식은 함수여야 한다. 이 함수는 context의 현재 value(Provider가 주는 value)를 받고 React 노드를 반환한다. 이 함수가 받는 value 값은 해당 context의 Provider 중 상위 트리에서 가장 가까운 Provider의 value prop과 동일하다. 상위에 Provider가 없다면 value 값은 createContext()
에 인자로 보냈던 defaultValue
와 동일하다.
Example1이 잘 만들어졌나 렌더링해보자.
// App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import Example1 from './components/Example1';
export default function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<Example1 />
</header>
</div>
);
}
persons 데이터를 잘 받아온 것을 알 수 있다.
- context 가져온다.
- 컨텍스트, 컨슈머 사용한다.
<PersonContext.Consumer>
- value 사용한다.
// ./components/Example2.jsx
import React from 'react';
import PersonContext from '../contexts/PersonContext';
export default class Example2 extends React.Component {
static contextType = PersonContext;
render() {
return <ul>{JSON.stringify(this.context)}</ul>;
}
}
// Example2.contextType = PersonContext;
contextType이라는 클래스 변수(정적 프로퍼티)를 생성하고 값은 PersonContext를 할당한다. 그러면 해당 클래서 안에서 this.context
를 이용해 해당 Context의 가장 가까운 Provider를 찾아 그 값을 읽을 수 있게 된다.
this.context
는 Provider로부터 받은 value 와 같다.(중요)
- static contextType에 컨텍스트를 설정
- this.context === value
// ./components/Example3.jsx
import React, { useContext } from 'react';
import PersonContext from '../contexts/PersonContext';
const Example3 = () => {
const value = useContext(PersonContext);
return <ul>{JSON.stringify(value)}</ul>;
};
export default Example3;
- useContext로 컨텍스트를 인자로 호출한다.
useContext(PersonContext)
- useContext의 리턴이 value이다.
Context 객체는 displayName
문자열 속성을 설정할 수 있다. 이 속성을 사용해서 context를 어떻게 보여줄지 결정한다.
예를 들어, 아래 컴포넌트는 개발자 도구에 MyDisplayName
로 표시된다.
// PersonContext.jsx
import React from 'react';
const PersonContext = React.createContext();
PersonContext.displayName = 'MyDisplayName';
export default PersonContext;