리액트를 다루는 기술 - 15장

velbie·2020년 11월 5일
0
post-thumbnail

Contenxt API 사용법 익히기

yarn create react-app context-tutorial

Context를 만듭니다.

//contexts/color.js

import { createContext } from "react";

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

export default ColorContext;

Consumer라는 컴포넌트를 통해서 색상을 조회해봅니다.

//components/ColorBox.js

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;

컴포넌트의 children이 있어야할 자리에 일반 JSX 나 함수를 전달!! (Render Props)

App에 렌더링 하면

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

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

export default App;


이렇게 검은색으로 나옵니다.
Provider 를 사용해서 Context의 value의 값을 변경할수 있습니다.

import React from "react";
import ColorBox from "./components/ColorBox";
import ColorContext from "./context/color";

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

export default App;


provider에는 value를 꼭 명시해주어야합니다.

동적 Context 사용하기

Context 값을 업데이트 해야하는 경우 어떻게 해야 하는지 알아보겠습니다.
??엥? Provider를 사용하면 되는거 아니였나요?? 초기값 변경은 되고 클릭했을때 값 바꾸고 이런건 안되나보다..

아래 코드는 Context와 Provider 컴포넌트로 구성되어있습니다.
Provider 컴포넌트에서 상태와 업데이트함수들을 Context로 넘겨봅니다.

// contexts/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;

// ColorProvider와 ColorConsumer 내보내기
export { ColorProvider, ColorConsumer };

export default ColorContext;

위 파일에서 ColorProvider 라는 컴포넌트를 새로 작성해 주었습니다.

컴포넌트는 props를 input으로 하고 UI가 어떻게 보여야 하는지 정의하는 React Element를 output으로 하는 함수입니다

그리고 그 컴포넌트에서 ColorContext.Provider를 렌더링하고 있습니다.
이 Provider의 value에는 상태는 state로 업데이트 함수는 actions로 묶어서 전달하고 있습니다. Context에서 값을 동적으로 사용할 때 반드시 묶어줄 필요는 없지만, 이렇게 state와 actions 객체를 다로따로 분리해 주면 나중에 다른 컴포넌트에서 Context의 값을 사용할 때 편합니다.

추가로 createContext를 사용할 때 기본값으로 사용할 객체도 수정했습니다. createContext의 기본값은 실제 Provider의 value에 넣는 객체의 형태와 일치시켜 주는 것이 좋습니다. 그렇게 하면 Context코드를 볼 때 내부 값이 어떻게 구성되어 있는지 파악하기도 쉽고, 실수로 Provider를 사용하지 않았을 때 리액트 애플리케이션 에러가 발생하지 않습니다.

-> 요약해보자면 Update 함수를 Context로 넘겼다
App 컴포넌트에서 ColorContext.Provider를 ColorProvider로 대체해보겟습니다.

// 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 도 마찬가지로 ColorContext.Consumer를 ColorConsumer로 변경하세요

// components/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;

위 코드에서 destructuring 을 사용하면 <ColorConsumer> 태그 안에서

  {({ state }) => (
        <>
          <div
            style={{
              width: "64px",
              height: "64px",
              background: state.color,
            }}
          />

          <div
            style={{
              width: "32px",
              height: "32px",
              background: state.subcolor,
            }}
          />
        </>
      )}

이렇게 사용할수 있습니다.


이제 클릭했을 때 색상바꾸는 예제를 만들어보겟습니다.
Context의 action들을 사용하기위해!

// components/SelectColor.js
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 컴포넌트에서 위에 코드 렌더링

// App.js

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

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

export default App;

이제 해당 SelectColors에서 마우스왼쪽, 오른쪽 클릭하면 색상 변경하도록 구현해보겠습니다.

// components/SelectColor.js
import React from "react";
import { 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 사용하는 것도 뒤에 있는데.. 그냥 스킵하겠습니다.

profile
안녕하세요

0개의 댓글