Context API

solie·2021년 9월 13일
0

context API는 리액트 프로젝트에서 전역적으로 사용할 데이터가 있을 때 유용한 기능이다.

Context API 를 사용한 전역상태 관리 흐름 이해

기존에는 최상위 컴포넌트에서 여러 컴포넌트를 거쳐 props 로 원하는 상태와 함수를 전달 했지만, Context API를 사용하면 Context 를 만들어 단 한번에 원하는 값을 받아 와서 사용할 수 있다.

Context API 사용법

  1. 리액트 프로젝트 새로 생성
    $ yarn create react-app context-tutorial

  2. 새로운 Context생성

<contexts/color.js>
import { createContext } from 'react';

const ColorContext = createContext({color: 'black'});

export default ColorContext;

새 Context를 만들 때는 createContext 함수를 사용한다. 파라미터에는 해당 Context의 기본 상태를 지정한다.

  1. ColorBox 라는 컴포넌트를 만들어 ColorContext안에 즐어 있는 색상을 보여준다.
import React from 'react';
import ColorContext from '../contexts/color';

const ColorBox = () => {
    return (
        <ColorContext.Consumer>
            {value => (
                <div
                    style={{
                        width: '64px',
                        height: '64px',
                        background: 'value.color'
                    }}
                 />
            )}
        </ColorContext.Consumer>
    )
}

export default ColorBox;

색상을 props 로 받아 오는 것이 아니아 ColorContext 안에 들어 있는 consumer라는 컴포넌트를 통해 색사을 조회
-> Consumer 사이에 중괄호를 열어서 그 안에 함수를 넣어준다. 이러한 패턴을 Function as a child, 혹은 Render Props라고 한다. 컴포넌트의 children이 있어야할 자리에 일반 JSX혹은 문자열이 아닌 함수를 전달하는것

  1. Provider 로 value 덮어 쓰기
<App.js>
import React from 'react';
import ColorBox from './components/ColorBox';
import  ColorContext from './contexts/color';

const App = () => {
  return (
    <ColorContext.Provider value= {{ color : 'red'}}>
      <div>
        <ColorBox />
      </div>
    </ColorContext.Provider>
  );
};

export default App;

기존에 createContext 함수를 사용할 때는 파라미터로 Context 의 기본값을 넣어 주었다.
이 기본값은 Provider를 사용하지 않을 때만 사용된다. 만약 Providr 는 사용했는데 value를 명시하지 않았다면, 이 기본값을 사용하지 않기 때문에 오류가 발생한다.

Provider 를 사용할 때는 value 값을 명시해 주어야 제대로 작동한다는 것을 명심하자

동적 context 사용하기

context의 value 에는 무조건 상태 값만 있어야 하는 것은 아니다. 함수를 전달해 줄 수도 있다.

<contexts/color.js>
import { createContext, useState } from 'react';

const ColorContext = createContext({
    state: { color: 'black', subcolor: 'red' },
    actions: {
        setColor: () => {},
        setSubcolor: () => {}
    }
});

const ColorProvider = ({children}) => {
    const [color, setColor] = useState('black');
    const [subcolor, setSubcolor] = useState('red');

    const value = {
        state: {color, subcolor},
        actions: {setColor, setSubcolor}
    };
    return (
        <ColorContext.Provider value={value}>{children}</ColorContext.Provider>
    );
};

//const ColorConsumer = ColorContext.Consumer와 같은 의미
const { Consumer: ColorConsumer } = ColorContext;

// ColorProvider와 ColorCunsumer 내보내기
export { ColorProvider, ColorConsumer };

export default ColorContext;

ColorProvider 라는 컴포넌트를 새로 작성해 주었다. 그리고 그 컴포넌트에서 ColorContext.Provider를 렌더링 하고 있다.
이 Provider의 value 에는 상태는 state로, 업데이트 함수는 actions 로 묶어서 전달하고 있다.

색상 선택 컴포넌트 만들기

<components/ColorBox.js>
import React from 'react';
import {ColorConsumer} from '../contexts/color';

const ColorBox = () => {
    return (
        <ColorConsumer>
            {value => (
                <>
                <div 
                    style={{
                        width: '64px', 
                        height: '64px', 
                        background: value.state.color
                        }}
                 />
                <div 
                    style={{
                        width: '32px',
                        height: '32px',
                        background: value.state.subcolor
                        }}
                 />
                </>
            )}
        </ColorConsumer>
    );
};

export default ColorBox;

App.js 에 렌더링 해준다

-> 마우스 좌클릭클릭은 큰 정사각형의 색상을 변경하고, 마우스 우클릭은 작은 정사각형의 색상을 변경하도록 구현.

<components/SelectColors.js>
import React from 'react';
import {ColorConsumer} from '../contexts/color';

const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'imdigo', '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;

마우스 우클릭 이벤트는 onContextMenu 를 사용하면 된다. 우클릭시 원래 브라우저 메뉴가 나타나지만 , 여기서 e.preventDefault()를 호출하면 메뉴가 뜨지 않는다.

정리.

기존에는 컴포넌트 간에 상태를 교류해야 할때 무조건 부모 -> 자식 흐름으로 props 를 통해 전달 해주었다. 이제는 Context API 를 통해 더욱 쉽게 상태를 교류할 수 있게 되었다.

전역적으로 여기저기서 사용되는 상태가 있고 컴포넌트의 개수가 많은 상황이라면 Context API를 사용하는 것이 좋다.

profile
2개월차 FE지망

0개의 댓글