Context API와 전역상태관리

jonyChoiGenius·2023년 1월 9일
0

React.js 치트 시트

목록 보기
10/22

context API를 활용한 전역상태관리

상태 패턴 (State Pattern)

디자인 패턴 중 상태 패턴은 Context 클래스에서 인터페이스를 제공하여 State로 캡슐화하는 것을 의미한다.
참조

리액트에서의 Context는 전역적(global)으로 데이터를 공유하기 위해 사용되도록 디자인되었다. 즉 데이터 간의 간격과 컴포넌트 트리의 계층이 없이 데이터를 공유할 수 있다. 16.3버전부터 추가되었다.

Context API

context 안에 {color: 'black'}이라는 값을 넣어 해당 값을 전역적으로 사용하는 예제이다.

  1. createContext
    @/contexts/color.js 라는 새로운 컨텍스트 파일을 만들자.
import { createContext } from "react";

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

export default ColorContext;
  1. CONTEXT.Consumer
    해당 콘텍스트는 컴포넌트의 형태로 다른 컴포넌트에서 사용된다.
    이때 Function as a child 혹은 Render Props라 불리는 패턴으로 컴포넌트 안에 value를 갖는 함수가 사용된다.
    @/components/ColorBox.js
import ColorContext from "../contexts/color";

const ColorBox = () => {
  return (
    <ColorContext.Consumer>
      {(value) => (
        <div
          style={{
            width: "64px",
            height: "64px",
            background: value.color, //color: 'black'
          }}
        />
      )}
    </ColorContext.Consumer>
  );
};
  1. CONTEXT.Provider
    상위 컴포넌트에서 context를 수정할 수 있다. 이때 value 프로퍼티를 필수로 가지고 있어야 한다.

@/App.js

import ColorBox from "./components/ColorBox";
import ColorContext from "./comtexts/color";

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

export default App;

동적 컨텍스트 사용하기

Context는 함수 등 다양한 값을 지니고 있을 수 있다.
아래는 조금 더 복잡한 예시이다.

@/contexts/color.js

import React, { 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와 ColorConsumer 내보내기
export { ColorProvider, ColorConsumer };

export default ColorContext;

@/App.js

import React from "react";
import ColorBox from "./components/ColorBox";
import { ColorProvider } from "./contexts/color";
import SelectColors from "./components/SelectColors";

const App = () => {
  return (
    <ColorProvider>
      <div>
        <SelectColors />
        <ColorBox />
      </div>
    </ColorProvider>
  );
};

export default App;

useContext Hook

ColorContext 모듈의 state를 구조분해 할당으로 가져온 예시이다.

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;

Class의 contextType 프로퍼티 사용하기

클래스형 컴포넌트 컴포넌트명.contextType을 통하여 this.context에 createContext()로 생성된 컨텍스트를 바인딩할 수 있다.

이 경우 하나의 context만 바인딩 됨에 유의하자.
(여러 컨텍스트를 사용하는 경우 CONTEXT.Provider를 통해 프로퍼티를 넘겨주어야 한다.)

Babel을 통해서 Static 클래스 필드를 사용하면 아래와 같이 정의할 수 있다.

import React, { Component } from "react";
import ColorContext from "../contexts/color";

const colors = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];

class SelectColors extends Component {
  static contextType = ColorContext;

  handleSetColor = (color) => {
    this.context.actions.setColor(color);
  };

  handleSetSubcolor = (subcolor) => {
    this.context.actions.setSubcolor(subcolor);
  };

  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;
profile
천재가 되어버린 박제를 아시오?

0개의 댓글