Link Search Menu Expand Document

Context API

  • 리액트 프로젝트에서 전역적으로 사용할 데이터를 관리
    • 사용자 로그인 정보, 애플리케이션 환경 설정, 테마 등
  • 리덕스, 리액트 라우터, style-components 등이 Context API 기반으로 구현

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

  • 리액트 애플리케이션에서 전역적으로 사용할 데이터는 최상위 컴포넌트인 Appstate에 넣어서 관리

전역 상태 관리 흐름

const [value, setValue] = useState('hello');
const onSetValue = useCallback(value => setValue(value), []);

전역 상태 관리 흐름

  • G 컴포넌트가 전역 상태를 업데이트 / F와 J 컴포넌트가 업데이트된 상태를 렌더링
  • App이 지니고 있는 value 값을 F와 J 컴포넌트에 전달
    • App-A-B-F
    • App-H-J
  • G 컴포넌트에 상태 업데이트 함수를 전달
    • App-A-B-E-G
  • 유지 보수성이 낮아짐

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

  • Context API를 통하여 복잡한 경로를 거치지 않고 전역 상태를 관리

Context API 사용법 익히기

  • createContext: 새로운 컨텍스트 생성
const ColorContext = createContext({ color: 'black '});
  • Consumer: Context 내의 상태를 받아옴
const ColorBox = () => {
    return (
        <ColorContext.Consumer>
            {value => (
                 <div
                     style= {{
                         width: '64px',
                         height: '64px',
                         background: value.color
                    }}
                />
             )}
        </ColorContext.Consumer>
    );
} ;
  • ConsumerColorContext 내의 color를 사용함

  • Provider: Context 내의 상태를 변경함

const App = () => {
    return (
        <ColorContext.Provider value={{ color: 'red'}}>
            <div>
                <ColorBox />
            </div>
        </ColorContext.Provider>
    );
};
  • ColorContext 내의 colorred로 변경됨
  • value 값을 명시하지 않을 경우 오류 발생

동적 Context 사용하기

  • createContext(value)value로 함수를 전달할 수 있음
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와 ColorConsumer 내보내기
export { ColorProvider, ColorConsumer };

export default ColorContext;
  • 위와 같이 상태와 함수를 분리할 경우 다른 컴포넌트에서 Context 값을 사용하기 편리

Consumer 대신 Hook 또는 static contextType 사용하기

useContext

  • useContext라는 Hook을 사용하여 함수 컴포넌트에서 Context를 편하게 사용 가능
  • useContext 적용 전
const ColorBox = () => {
    return (
        <ColorConsumer>
            {({ state }) => (
                <>
                    <div
                        style={{
                            width: '64px',
                            height: '64px',
                            background: state.color
                        }}
                    />
                    <div
                        style={{
                            width: '32px',
                            height: '32px',
                            background: state.subcolor
                        }}
                    />
                </>
            )}
        </ColorConsumer>
    )
}

export default ColorBox;
  • useContext 적용 후
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;
  • children에 함수를 전달하는 Render Props 패턴 대신 간결하게 Context 조회 가능

Render Props 패턴?

const RenderPropsSample = ({ children }) => {
    return <div>결과: {children(5)}</div>;
}

<RenderPropsSample>{value => 2 * value}</RenderPropsSample>

// 결과: 10

static contextType

  • static contextType을 사용하여 클래스형 컴포넌트에서 Context를 좀 더 쉽게 사용할 수 있음
class SelectColors extends Component {
    static contextType = ColorContext;
    
    handleSetColor = color => {
        this.context.actions.setColor(color);
    }
}
  • 한 클래스에서 하나의 Context 만을 사용할 수 있으므로 함수형 컴포넌트와 useContext를 사용하는 것을 권장

정리

  • 기존에는 컴포넌트 간에 상태를 교류할 때 무조건 props를 통해 전달해야 했음
  • Context API를 이용하여 더욱 쉽게 상태를 교류하는 것이 가능
  • 단순한 전역 상태 관리에서는 Context API를 사용해도 되지만 대부분의 경우 리덕스를 사용하는 것을 권장