티스토리 뷰

front-end/React

리액트 Context API

이안_ian 2019. 12. 15. 16:46




반응형

리액트 앱은 컴포넌트 간에 데이터를 props로 전달하기 때문에 컴포넌트가 여기저기서 필요한 데이터가 있을 때 주로 최상위 컴포넌트인 App의 state에 넣어서 관리합니다. 만약 C 컴포넌트가 전역 상태를 업데이트 시키는 기능을 담당한다면 App에서는 const [value, setValue] = useState('hello'); 생성하여 App > A > B > C 순으로 전달해야 합니다. 이렇게 여러 번에 거쳐서 전달하게 될 경우 유지 보수성이 낮아질 가능성이 높기 때문에 Context API를 사용하여 Context에 만들어서 단 한 번에 원하는 값을 받아와 사용할 수 있습니다.

import { createContext } from "react";

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

export default ColorContext;

이런식으로 color Context를 만들어 봅시다. 그리고 ColorBox라는 컴포넌트를 만들어서 ColorContext안에 들어 있는 색상을 보여주겠습니다. 이때 색상을 props로 받아 오는 것이 아니라 ColorContext안에 들어 있는 Consumer라는 컴포넌트를 통해 색상을 조회할 것입니다.

import React from "react";
import ColorContext from "../contexts/color";

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

export default ColorBox;

Consumer 사이에 중괄호를 열어서 그 안에 함수를 넣어 주었습니다. 이러한 패턴을 Function as a child, 혹은 Render Props라고 합니다. 컴포넌트의 children이 있어야 할 자리에 일반 JSX혹은 문자열이 아닌 함수를 전달하는 것이죠.

import React from "react";
import ColorBox from "./component/ColorBox";

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

export default App;

 렌더링 해봅시다.

Provider

provider를 사용하면 Context의 value를 변경할 수 있습니다. 주의해야할 점이 하나 있는데 그것은 provider를 사용할 때 꼭 value의 값을 명시해주어야 작동한다는 것입니다. App 컴포넌트를 다음과 같이 수정해보세요.

import React from "react";
import ColorBox from "./component/ColorBox";
import ColorContext from "./contexts/color";

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

export default App;

동적 Context 사용하기

Context의 value에는 무조건 상태 값만 있어야 하는 것은 아닙니다. 함수를 전달해 줄 수도 있습니다. 기존의 코드를 다음과 같이 수정해보세요.

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;
import React from "react";
import ColorBox from "./component/ColorBox";
import { ColorProvider } from "./contexts/color";

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

export default App;
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;

색상 선택 컴포넌트 만들기

이번에는 Context의 actions에 넣어 준 함수를 호출하는 컴포넌트를 만들어보겠습니다.

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>
    </div>
  );
};

export default SelectColors;
import React from "react";
import ColorBox from "./component/ColorBox";
import ColorContext from "./contexts/color";
import { ColorProvider } from "./contexts/color";
import SelectColors from "./component/SelectColors";

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

export default App;

이제 해당하는 SelectColors에서 마우스 클릭하면 큰 정사각형이 바뀌고, 마우스 오른쪽 클릭하면 작은 정사각형이 바뀌도록 하겠습니다.

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;

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

 

 

 

 

 

 

 

출처: 리액트를 다루는 기술

반응형

'front-end > React' 카테고리의 다른 글

리액트 서버 사이드 렌더링의 이해  (0) 2019.12.31
리액트 라우터 적용해보기  (0) 2019.12.13
리액트 SPA 요점  (0) 2019.12.11
리액트 Hook #2  (0) 2019.12.08
리액트 Hooks  (0) 2019.12.07
댓글
반응형
최근에 달린 댓글
글 보관함
Total
Today
Yesterday
최근에 올라온 글
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30