리액트 Summary - 4-1. React Context API 총정리-thumbnail

리액트 Summary - 4-1. React Context API 총정리

React Context API summary
315

Context API

많은 블로그 글에서 Context API를 설명할 때 Consumer를 가지고 하지만, 난 왜 아주 간편해보이는 useContextstatic contextType를 더 먼저 설명하지 않는지 아주 답답한 지경이었다. 답답하면 내가 그렇게 정리하면 된다.

우선적으로 위의 둘에 대해서 정리를 먼저 하고, 차후에 기회가 된다면 Consumer를 활용하는 방식도 올리는 쪽으로 하자.

useContext

(src/context.js)

import { createContext, useState } from 'react';

const MyContext = createContext({
  state: {color: 'red', fontSize: 20},
  actions: {
    setColor: () => {},
    setFontSize: () => {}
  }
});

const MyProvider = ({ children }) => {
  const [color, setColor] = useState('red');
  const [fontSize, setFontSize] = useState(20);

  const value = {
    state: { color, fontSize },
    actions: { setColor, setFontSize }
  };

  return (
    <MyContext.Provider value={value}>{children}</MyContext.Provider>
  );
}

const { Consumer: MyConsumer } = MyContext; // const MyConsumer = MyContext.Consumer;

export { MyProvider, MyConsumer };

export default MyContext;

context.js의 코드만 이해하면 Context API는 끝났다고도 볼 수 있다. 우선 첫 번째 파트부터 보자.

createContext

import { createContext } from 'react';

const MyContext = createContext({
  state: {color: 'red', fontSize: 20},
  actions: {
    setColor: () => {},
    setFontSize: () => {}
  }
});

새 context를 만들어주는 부분이다. state에는 상태를, actions에는 상태들을 변경해줄 메서드를 우선 넣어두었다. 해당 내용들은 Provider가 지정되지 않았을 때 기본값으로 작동시킬 내용을 임의로 넣어주는 것일 뿐이다. 해당 내용들은 차후에 Provider를 추가하면 더 이상 신경쓰지 않아도 되는 값들이 된다.

Provider & Render props

import { useState } from 'react';

const MyProvider = ({ children }) => {
  const [color, setColor] = useState('red');
  const [fontSize, setFontSize] = useState(20);

  const value = {
    state: { color, fontSize },
    actions: { setColor, setFontSize }
  };

  return (
    <MyContext.Provider value={value}>{children}</MyContext.Provider>
  );
}

핵심이 되는 부분이다. 우선 useState를 사용해 state가 될 기본값들과 actions에 들어갈 set 함수들을 만든다. 여기서는 예시로 color와 fontSize를 선택했다. 그리고 난 뒤 Myprovider가 위에서 만들었던 MyContext의 Provider를 return하도록 설계한다. 여기서는 코드가 이렇게 된다. <MyContext.Provider value={value}>{children}</MyContext.Provider>

여기서 MyProvider와 그 return 값에 있는 {children}이 무엇인지 잠깐 짚고 넘어가자. 이런 형식의 코드는 Render props라고 불리우는데, 이건 MyProvider가 어떻게 활용되고 있는지를 보고 이해하면 더 편하다. App.js로 가보자.

(src/App.js)

import { MyProvider } from './context';
import Child from './Child';
import Child2 from './Child2';

const App = () => {
  return (
    <MyProvider>
      <div>
        <Child />
        <Child2 />
      </div>
    </MyProvider>
  );
}

export default App;

코드를 보면 children prop으로 <div><Child /><Child2 /></div>가 전달되고 있다는 것을 알 수 있다(예전 글에서도 보았지만, children prop은 태그 사이에 쓰여있는 text를 뜻한다). 그렇게 전달받은 children components를 MyContext.Provider 안에 넣어 return하게 되면 해당 component들이 rendering된다.

여기에 value 값으로 state와 actions가 각각 담긴 객체를 전달하고 있다. 굳이 state나 actions라는 이름으로 정하지 않아도 되고 한꺼번에 다 담아도 상관은 없으나, 어떤 것들이 전달되고 있는지를 명확하게 명시하기 위해서 state와 actions라는 이름으로 전달했다. 다만 property name value는 지켜주어야 한다(value={value}).

export & how to use

const { Consumer: MyConsumer } = MyContext; // const MyConsumer = MyContext.Consumer;

export { MyProvider, MyConsumer };

export default MyContext;

마지막 부분을 확인해보자. MyProvider와 MyConsumer를 전달하고 있다. 물론 뒤의 코드에서는 MyProvider만 사용되므로(위에서 확인한 App.js에서 component들을 감싸는 요소로 MyProvider를 사용했음을 기억해보자), MyConsumer는 굳이 export하지 않아도 되긴 한다. MyContext도 export해주어 Child component와 Child2 component에서 Context API를 활용, props를 쓰지 않고도 전역적으로 특정 상태나 메서드에 접근할 수 있게 해주었다. 두 component의 코드를 아래에서 확인해보자.

(src/Child.js)

import { useContext } from 'react';
import MyContext from './context';

const Child = () => {
  const { state } = useContext(MyContext);

  return (
    <>
      <p
        style={{
          color: state.color,
          fontSize: state.fontSize
        }}
      >
        Child Example
      </p>
    </>
  );
}

export default Child;

(src/Child2.js)

import { useContext } from 'react';
import MyContext from './context';

const Child2 = () => {
  const { actions } = useContext(MyContext);

  const handleSetColor = () => {
    actions.setColor('black');
  }
  const handleSetFontSize = () => {
    actions.setFontSize(30);
  }

  return (
    <>
      <button onClick={handleSetColor}>
        color to black
      </button>
      <button onClick={handleSetFontSize}>
        font to 30px
      </button>
    </>
  );
}

export default Child2;

너무 간단하다. React에서 useContext를 가져오고, 그 안에 들어 있는 state나 메서드를 가져와서 사용하면 된다.

static contextType

거의 동일하다고 보면 된다. Class component에서만 쓰이고 워낙 유사하다보니, 예시 코드로 갈음하고 넘어가자.

import { Component } from 'react';
import MyContext from './context';

class Child extends Component {
  static contextType = MyContext;

  render() {
    return (
      <>
        <p
          style={{
            color: this.context.state.color,
            fontSize: this.context.state.fontSize
          }}
        >
          Child Example
        </p>
      </>
    );
  }
}

export default Child;

static contextType = MyContext;로 불러온 뒤 this.context로 Context API에 담긴 내용들에 접근할 수 있다.


참고 서적 :
김민준, 2019, 길벗, 『리액트를 다루는 기술, 개정판』