컨텍스트(Context) 객체는 React 애플리케이션에서 데이터를 전역적으로 공유하기 위한 메커니즘을 제공하는 객체입니다. 이 객체를 사용하면 중간 컴포넌트를 거치지 않고 컴포넌트 간에 데이터를 전달할 수 있습니다. 컨텍스트 객체는 React.createContext 함수를 사용하여 생성됩니다. 생성된 컨텍스트 객체에는 Provider와 Consumer라는 두 가지 주요 속성이 있습니다.
React.createContext 함수는 컨텍스트 객체를 생성합니다. 이 함수는 초기값을 인자로 받을 수 있습니다. 초기값은 컨텍스트를 사용하는 컴포넌트에서 해당 컨텍스트의 공급자가 값을 제공하지 않을 때 사용됩니다. React.createContext 함수를 호출하면 두 가지 속성(context.Provider, context.consumer)을 가지는 컨텍스트 객체가 반환됩니다.
const MyContext = React.createContext(initialValue);
컨텍스트 값을 제공하는 컴포넌트입니다. Provider 컴포넌트를 사용하여 컨텍스트 값을 설정하고, 하위 컴포넌트에서 해당 값을 사용할 수 있습니다.
<MyContext.Provider value={value}>
{/* 하위 컴포넌트 */}
</MyContext.Provider>
컨텍스트 값을 소비하는 컴포넌트입니다. Consumer 컴포넌트를 사용하여 컨텍스트 값을 읽어올 수 있습니다. React의 클래스 컴포넌트에서는 MyContext.Consumer로 사용하며, 함수형 컴포넌트에서는 MyContext를 직접 사용할 수 있습니다.
<MyContext.Consumer>
{value => (
// value를 사용하여 컨텍스트 값에 접근
)}
</MyContext.Consumer>
// 컨텍스트 객체 생성
const MyContext = React.createContext();
// 데이터를 공유할 상위 컴포넌트
class ParentComponent extends React.Component {
state = {
value: 'Hello, World!'
};
render() {
return (
<MyContext.Provider value={this.state.value}>
<ChildComponent />
</MyContext.Provider>
);
}
}
// 데이터를 사용할 하위 컴포넌트
class ChildComponent extends React.Component {
render() {
return (
<div>
<h1>Child Component</h1>
<MyContext.Consumer>
{value => <p>{value}</p>}
</MyContext.Consumer>
</div>
);
}
}
// 애플리케이션
class App extends React.Component {
render() {
return <ParentComponent />;
}
}
ReactDOM.render(<App />, document.getElementById('root'));
// 컨텍스트 객체 생성
const MyContext = React.createContext();
// 데이터를 공유할 상위 컴포넌트
function ParentComponent() {
const value = 'Hello, World!';
return (
<MyContext.Provider value={value}>
<ChildComponent />
</MyContext.Provider>
);
}
// 데이터를 사용할 하위 컴포넌트
function ChildComponent() {
return (
<div>
<h1>Child Component</h1>
<MyContext.Consumer>
{value => <p>{value}</p>}
</MyContext.Consumer>
</div>
);
}
// 애플리케이션
function App() {
return <ParentComponent />;
}
ReactDOM.render(<App />, document.getElementById('root'));
React.useContext는 React Hooks의 하나로, 함수형 컴포넌트에서 컨텍스트(Context) 값을 간편하게 조회하기 위해 사용되는 Hook입니다. React.useContext를 사용하면 컨텍스트 객체의 값을 직접 읽어올 수 있으며, 클래스 컴포넌트의 static contextType 또는 Consumer를 사용하는 것보다 간단하고 간결한 코드를 작성할 수 있습니다.
function ChildComponent() {
const value = React.useContext(MyContext);
return (
<div>
<h1>Child Component</h1>
<p>{value}</p>
</div>
);
}
Context에 의한 렌더링은 다음과 같은 과정을 거칩니다.
1. Provider를 렌더링했을 때 Context Provider에 새로운 값이 전달되었는지 여부를 체크
2. 만약 Provider의 값이 새로운 참조값이라면 Context를 소비하는 컴포넌트를 업데이트
아래의 소스를 예시로 들었을때, ParentComponent가 렌더링 될 때마다, React는 MyContext.Provider가 새로운 값을 받았다는 것을 알아차릴 것이고, 서브 트리를 하나씩 돌면서 MyContext를 소비하는 컴포넌트를 찾을 것입니다. Context Provider가 새로운 값을 가질 때면, Context를 사용하는 모든 중첩된 컴포넌트는 리렌더링이 될 것입니다.
function GrandchildComponent() {
const value = useContext(MyContext);
return <div>{value.a}</div>
}
function ChildComponent() {
return <GrandchildComponent />
}
function ParentComponent() {
const [a, setA] = useState(0);
const [b, setB] = useState("text");
const contextValue = {a, b};
return (
<MyContext.Provider value={contextValue}>
<ChildComponent />
</MyContext.Provider>
)
}
React는 기본적으로 부모 컴포넌트가 렌더링되면, 그 안에 있는 모든 자식 컴포넌트를 재귀적으로 렌더링됩니다. React는 "Props가 변경되었는지 여부"와는 상관없이 그저 부모 컴포넌트가 렌더링 된다면 무조건 모든 자식 컴포넌트들을 렌더링합니다. 따라서 위의 코드에서 ParentComponent가 랜더링 되면 그의 자식인 ChildComponent가 랜더링 되고 또 그의 자식인 GrandchildComponent가 랜더링 됩니다. 그렇지만 우리가 원하는 것은 Context를 가지지 않는 ChildComponent는 리랜더링 되지 않게 하는 것입니다! 이를 위해서 우리는 useMemo를 사용해야 합니다.
function GreatGrandchildComponent() {
return <div>Hi</div>
}
function GrandchildComponent() {
const value = useContext(MyContext);
return (
<div>
{value.a}
<GreatGrandchildComponent />
</div>
}
function ChildComponent() {
return <GrandchildComponent />
}
const MemoizedChildComponent = React.memo(ChildComponent);
function ParentComponent() {
const [a, setA] = useState(0);
const [b, setB] = useState("text");
const contextValue = {a, b};
return (
<MyContext.Provider value={contextValue}>
<MemoizedChildComponent />
</MyContext.Provider>
)
}
이렇게 소스를 수정하게 되면 아래와 같은 순서로 React가 작업을 하게 됩니다.🧐
React.memo()
로 감싸져있는 것을 발견합니다. Props를 전달받고있지 않기 때문에 실제로 변경되는 Props는 없습니다. 따라서 React는 ChildComponent 전체 렌더링을 건너 뛸 것입니다.새로운 Context 값
이 있기 때문에 리렌더링이 필요하다는 것도 알아챕니다. React는 더 진행해서 GrandchildComponent를 리렌더링 합니다. Context의 변경으로 인한 리렌더링이죠.