Context API에 대해 공부ㄱㄱ

Daniel Lim·2021년 4월 28일
0
post-thumbnail

Context API는 사용자 로그인정보, Application 환경설정, 테마 같이 프로젝트에서 전역적으로 사용할 데이터가 있는 경우 사용하면 유용한 기능이다.

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

리액트에서는 데이터를 props로 전달하는데, 최상위 Component가 App이라서 전역적으로 데이터를 전달하려면 App에 정의를 해야한다.

예를들어 App에서 C라는 component로 전달을 하기 위해서는 중간에 있는 A와 B를 거쳐야하는데 (App -> A -> B -> C) 만약 component가 많아질수록 거쳐야 되는 component도 많아진다. Component를 관리하기 복잡해 지는거다..

이런 상태를 관리하기 위해 리덕스같은 라이브러리를 사용했었는데, v16.3이후 Context API가 많이 개선이 되어 라이브러리 없이도 손쉽게 관리가 가능하다고 함.

Context API를 이용하게 되면 중간역할을 해주면서 전달을 해준다. 여러 component를 안거쳐도 되고 특정 component에서 context API를 통해 바로 데이터를 전달이 가능해진다.



Context 만드는 방법

프로젝트 폴더에서 context만 모아놓을 폴더를 만들면 관리하기 좋다.

context만 모아놓을 폴더 안에 color.js라는 파일을 만들어보겠음.

import { createContext } from 'react';

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

export default ColorContext;

createContext함수를 사용해줘야 context를 만들 수 있다. import 해줬다. 해당 함수의 parameter안에 기본 상태를 입력해줬다.



Consumer를 사용해서 Context 사용하기

ColorBox.js라는 component를 만들어줬다.
이 component에서 위에 color context만들어 놓은것을 사용해보겠음.

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;

context 만들었던것을 import 해줘야함.
import를 해준 ColorContext를 이용해서 <ColorContext.Consumer> 태그를 만들어줬다.

해당 태그 안에 {} 안에 value값을 불러오게 되고, background에 value.color를 입력하면서 색을 불러오게 된다.
이렇게 {}에 입력하는 방식을 Render Props라고 한다.



App.js에서 ColorBox를 렌더링을 해줘야함.

import React from 'react';
import ColorBox from './components/ColorBox';

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

export default App;

서버 실행하고 확인해보면 black 사각형 박스가 나온다. context에서 black 값을 불러옴.



Provider 사용해서 value 변경하기

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;

ColorContext를 import 해주고, 태그 만들어서 해당 태그에 Provider를 이용해서 red로 값을 적용해줬다.

Provider를 사용할 때 value를 명시해줘야지 안그러면 오류가 발생한다.



동적 Context 사용 방법

Context의 값이 동적으로 바뀌게 되는것을 만들어 보겠음.

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 { Consumer: ColorConsumer } = ColorContext;

export { ColorProvider, ColorConsumer };

export default ColorContext;

App.js

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

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

export default App;

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;

위의 코드를 객체 비구조화 할당 문법을 사용해서 value조회를 생략 가능.

ColorBox.js

import React from 'react';
import { ColorConsumer } from '../contexts/color';

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;


Context의 action에 넣어 준 함수 호출

SelectColor.js 파일을 component폴더에 생성ㄱㄱ

import React from 'react';

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

const SelectColors = () => {
  return (
    <div>
      <h2>색상을 선택하세요.</h2>
      <div style={{ display: 'flex' }}>
        {colors.map((color) => (
          <div
            key={color}
            style={{
              background: color,
              width: '24px',
              height: '24px',
              cursor: 'pointer',
            }}
          />
        ))}
      </div>
      <hr />
    </div>
  );
};

export default SelectColors;

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;

이번에는 해당 SelectColors에서 마우스 좌,우 클릭에 따라 색상 변경하게 만들어보겠음.

components/SelectColors.js

import React from 'react';
import ColorContext, { ColorConsumer } from '../contexts/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;


Consumer 대신 hook, static contextType 사용하는 방법

1. useContext Hook 사용하기

useContext hook를 사용하면 context를 아주 편하게 사용할 수 있다고 함.

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;

children에 함수를 전달하는 Render Props 방식 대신에 useContext Hook을 사용하면 훨씬 편하게 Context 값을 조회할 수 있음.

하지만 Hook은 함수형 컴포넌트에서만 사용이 가능함.
클래스형 컴포넌트에서는 Hook 사용불가.



static contextType 값을 클래스 상단에 지정ㄱ

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;
  render() {
    return (
      <div>
        <h2>색상을 선택하세요.</h2>
        <div style={{ display: 'flex' }}>
          {colors.map((color) => (
            <div
              key={color}
              style={{
                background: color,
                width: '24px',
                height: '24px',
                cursor: 'pointer',
              }}
            />
          ))}
        </div>
        <hr />
      </div>
    );
  }
}

export default SelectColors;

this.context를 조회했을 때 현재 Context의 value를 가리키게 됨.
this.context.actions.setColor라고 입력하면 setColor를 호출하게 됨.



SelectColors.js

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;

static contextType을 정의하면 class method서도 Context에 있는 함수를 호출할 수 있으나 클래스에서 하나의 Context만 사용이 가능하다.



2. static contextType 사용

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

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

class SelectColors extends Component {
  render() {
    return (
      <div>
        <h2>색상을 선택하세요.</h2>
        <div style={{ display: 'flex' }}>
          {colors.map((color) => (
            <div
              key={color}
              style={{
                background: color,
                width: '24px',
                height: '24px',
                cursor: 'pointer',
              }}
            />
          ))}
        </div>
        <hr />
      </div>
    );
  }
}

export default SelectColors;
profile
웹개발 잘하고 싶어요

0개의 댓글