- Context API는 리액트 프로젝트에서 전역적으로 사용할 데이터가 있을 때 유용한 기능이다.
- 리액트 관련 라이브러리(리덕스, 리액트 라우터, styled-components) 등이 Context API를 기반으로 구현되어 있다.
15.1 Context API를 사용한 전역 상태 관리 흐름 이해하기
- 리액트 애플리케이션은 컴포넌트 간에 데이터를 props로 전달하기 때문에 컴포넌트 여기저기서 필요한 데이터가 있을 때는 주로 최상위 컴포넌트인 App의 state에 넣어서 관리한다.
G 컴포넌트는 전역 상태를 업데이트 시키고, F와 J 컴포넌트는 업데이트된 상태를 렌더링한다고 가정해 보자.
그렇다면 App 컴포넌트에서는 다음과 같이 상태와 업데이트 함수를 정의해야 한다.
const [value, setValue] = useState('hello');
const onSetValue = useCallback(value => setValue(value),[]);
- 실제 리액트 프로젝트에서는 더 많은 컴포넌트를 거치거나 다뤄야 할 데이터가 훨씬 많아질 수도 있고, 이러한 방식은 유지 보수성을 낮출 수 있다.
- 그렇기 때문에 리덕스나 MobX와 같은 상태 관리 라이브러리를 사용하여 전역 상태 관리 작업을 더 편하게 처리하거나, Context API를 이용하면 별도의 라이브러리를 사용하지 않아도 전역 상태를 손쉽게 관리할 수 있다.
- 기존에는 최상위 컴포넌트에서 여러 컴포넌트를 거쳐 props로 원하는 상태와 함수를 전달했지만, Context API를 사용하면 Context를 만들어 단 한 번에 원하는 값을 받아와 사용할 수 있다.
15.2 Context API 사용법 익히기
1) 새 Context 만들기
2) Consumer 사용하기
ColorContext 안에 들어 있는 색상을 props로 받아 오는 것이 아니라 ColorContext 내의 Consumer 컴포넌트를 통해 조회할 것이다.
→ Consumer 사이에 중괄호를 넣어서 그 안에 함수를 넣어 주었고 이러한 패턴을 Function as a child, 혹은 Render Props라고 한다. 컴포넌트 children이 있어야 할 자리에 일반 JSX 혹은 문자열이 아닌 함수를 전달하는 것이다.
3) Provider
Provider를 사용하면 Context의 value를 변경할 수 있다.
→ 빨간색 정사각형이 나타난다.
15.3 동적 Context 사용하기
Context 값을 업데이트해야 하는 경우 어떻게 해야 하는지 알아보자.
1) Context 파일 수정하기
- ColorProvider 컴포넌트를 작성해 주었고, 이 컴포넌트에서는 ColorContext.Provider을 렌더링 한다.
- 이 Provider의 value에는 상태는 state, 업데이트 함수는 actions로 묶어서 전달하고 있다.
- createContext의 기본값은 실제 Provider의 value에 넣는 객체의 형태와 일치시켜 주는 것이 좋다.
2) 새로워진 Context를 프로젝트에 반영하기
위 코드에서 객체 비구조화 할당 문법을 사용하면 다음과 같이 value를 조회하는 것을 생략할 수도 있다.
3) 색상 선택 컴포넌트 만들기
이번에는 Context의 actions에 넣어 준 함수를 호출하는 컴포넌트를 만들어 보자.
이제 해당 SelectColors에서 마우스 왼쪽 버튼을 클릭하면 큰 정사각형의 색상을 변경하고, 마우스 오른쪽 버튼을 클릭하면 작은 정사각형의 색상을 변경하도록 구현해 보자.
components/SelectColors.js
import React from 'react';
import { ColorConsumer } from '../context/color';
const colors = ['red','orange','yellow','green','blue','indigo','violet'];
const SelectColors = ()=>{
return(
<div>
<h2>색상을 선택하세요.</h2>
<ColorConsumer>
{({actions})=>(
<div style={{display:'flex'}}>
{colors.map(color=>(
<div
key={color}
style={{
background:color,
width:'24px',
height:'24px',
cursor:'pointer'}}
onClick={()=>actions.setColor(color)}
//마우스 오른쪽 버튼 클릭 이벤트
onContextMenu={e=>{
e.preventDefault(); // 마우스 오른쪽 버튼 클릭 시 메뉴가 뜨는 것을 무시함
actions.setSubColor(color);
}}
/>
))}
</div>
)}
</ColorConsumer>
<hr/>
</div>
)
}
export default SelectColors;
15.4 Consumer 대신 Hook 또는 static contextType 사용하기
이번에는 Context에 있는 값을 사용할 때 Consumer 대신 다른 방식을 사용하여 값을 받아 오는 방법을 알아보자.
1) useContext Hook 사용하기
- 리액트에 내장되어 있는 Hooks 중에서 useContext를 사용하면, 함수형 컴포넌트에서 Context를 아주 편하게 사용할 수 있다.
- children에 함수를 전달하는 Render Props 패턴이 불편하다면, useContext Hook을 사용하여 훨씬 편하게 Context 값을 조회할 수 있다.
- Hook은 함수형 컴포넌트에서만 사용할 수 있다는 점을 주의하자.
components/ColorBox.js
import React, { useContext } from 'react'
import ColorContext from '../contexts/color'
const ColorBox = ()=>{
const {state} = useContext(ColorContext);
return(
<>
<div
style={{
width:'64px',
height:'64px',
background: state.color}}
/>
<div
style={{
width:'32px',
height:'32px',
background: state.subColor}}
/>
</>
)
}
export default ColorBox;
2) static contextType 사용하기
- 클래스형 컴포넌트에서 Context를 좀 더 쉽게 사용하고 싶다면 static contextType을 정의하는 방법이 있다.
- static contextType을 정의하면 클래스 메서드에서도 Context에 넣어 둔 함수를 호출할 수 있다는 장점이 있다.
- 단점은 한 클래스에서 하나의 Context밖에 사용하지 못한다는 것이다.
components/SelectColors.js
import React, { Component } from 'react';
import ColorContext from '../context/color';
const colors = ['red','orange','yellow','green','blue','indigo','violet'];
class SelectColors extends Component{
static contextType = ColorContext;
handleSetColor = color =>{
this.context.actions.SelectColors(color);
}
handleSetSubColor = color =>{
this.context.actions.setSubColors(color);
}
render(){
return(
<div>
<h2>색상을 선택하세요.</h2>
<div style={{display:'flex'}}>
{colors.map(color=>(
<div
key={color}
style={{
background:color,
width:'24px',
height:'24px',
cursor:'pointer'}}
onClick={()=>this.handleSetColor(color)}
onContextMenu={(e)=>{
e.preventDefault();
this.handleSetSubColor(color);
}}
/>
))}
</div>
<hr/>
</div>
)
}
}
export default SelectColors;
→ 이렇게 해 주면 this.context를 조회했을 때 현재 Context의 value를 가리키게 된다. 즉 setColor를 호출하고 싶다면 this.context.actions.setColor를 호출하면 되는 것이다.
15.5 정리
- 기존에는 컴포넌트 간에 상태를 교류해야 할 때 무조건 부모 → 자식 흐름으로 props를 통해 전달해 주었는데, 이제는 Context API를 통해 더욱 쉽게 상태를 교류할 수 있게 되었다.
- 프로젝트 컴포넌트 구조가 꽤 간단하고 다루는 상태의 종류가 그다지 많지 않다면, 굳이 Context를 사용할 필요는 없다.
- 전역적으로 여기저기서 사용되는 상태가 있고 컴포넌트의 개수가 많은 상황이라면 Context API를 사용하는 것을 권한다.
'React > [책] 리액트를 다루는 기술' 카테고리의 다른 글
10장. 일정 관리 웹 애플리케이션 만들기 (0) | 2022.04.15 |
---|---|
16장. 리덕스 라이브러리 이해하기 (0) | 2021.08.20 |
9장. 컴포넌트 스타일링 (0) | 2021.07.28 |
8장. Hooks (0) | 2021.07.28 |
7장. 컴포넌트의 라이프사이클 메서드 (0) | 2021.07.21 |