[React] 동적 Context 사용하기

겨레·2024년 12월 11일

[React] 리액트 스터디

목록 보기
84/95

앞서 공부한 내용은 고정적인 값만 사용할 수 있었던 예제임.
이번엔 Context 값을 업데이트해야 할 경우엔 어떻게 해야하는지 알아보자!


Context의 value에는 무조건 상태 값만 있어야 하는 것은 아님!!! 함수를 전달해 줄 수도 있음.

동적 Context 사용할 수 있다는 이야기!


  • 👉 기존 ColorContext.jsx 수정
import { useState, createContext } from "react";

// == 새 Context를 만들 때 ==
// => createContext 함수를 사용함.
// => 파라미터에는 해당 Context의 기본 상태를 지정함.
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;

  • ColorProvider라는 컴포넌트를 새로 작성함.

    • 그리고 그 컴포넌트에서는 ColorContext.Provider를 렌더링하고 있음. 이 Provider의 value에는 상태는 state로, 업데이트 함수는 actions로 묶어서 전달하고 있음.

    • Context에서 값을 동적으로 사용할 때 반드시 묶어 줄 필요는 없지만, 이렇게 state와 actions 객체를 분리하면 다른 컴포넌트에서 Context의 값을 사용할 때 편함.

  • 추가로 createContext를 사용할 때 기본값으로 사용할 객체도 수정함.

    • createContext의 기본값은 실제 Provider의 value에 넣는 객체의 형태와 일치시키는 게 좋음.

      그렇게 하면 Context 코드를 볼 때 내부 값이 어떻게 구성되어 있는지 파악하기 쉽고, 실수로 Provider를 사용하지 않았을 때 리액트 애플리케이션에서 에러가 발생하지 않음.




  • 👉 기존 ColorBox.jsx 수정

ColorBox도 마찬가지로 ColorContext.Consumer를 ColorConsumer로 변경한다.

사용할 value의 형태도 바뀌었으니 이에 따른 변화도 반영시켜보자!

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



  • App.jsx
import React from "react";
import "./App.css";
import ColorBox from "./components/ColorBox";
import { ColorProvider } from "./contexts/color";

function App() {
  return (
    // <ColorContext.Provider value={{ state: { color: "red", subColor: "blue" } }}>

    //   <div>
    //     <ColorBox />
    //   </div>
    // </ColorContext.Provider>
    <ColorProvider>
      <div>
        <ColorBox />
      </div>
    </ColorProvider>
  );
}

export default App;

실행하면... 이런 결과가 나온다.



여기서 더 나아가서 색상 선택 컴포넌트를 만들어보자!

  • SelectColors.jsx 파일 생성
    Context의 actions에 넣어 준 함수를 호출하는 SelectColors 컴포넌트를 만든다. (지금은 Consumer 사용하지 않고 UI만 준비)
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>
      <hr />
    </div>
  );
};

export default SelectColors;

App 컴포넌트에서 ColorBox 위에 렌더링해보자!

과연... 결과는??!


(+) 추가로 SelectColors에서 마우스 왼쪽 버튼을 클릭하면 큰 정사각형의 색상이 변경되고, 마우스 오른쪽 버튼을 클릭하면 작은 정사각형의 색상이 변경되게 해보자!

  • SelectColors.jsx 생성
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={() => {
                  console.log("왼쪽 마우스 클릭:", color); // 왼쪽 클릭 시 찍히는 값
                  actions.setColor(color); // 왼쪽 클릭 시 큰 색상 변경
                }}
                onContextMenu={(e) => {
                  e.preventDefault(); // 마우스 오른쪽 버튼 클릭 시 기본 메뉴 방지
                  console.log("오른쪽 마우스 클릭:", color); // 오른쪽 클릭 시 찍히는 값
                  actions.setSubColor(color); // 오른쪽 클릭 시 작은 색상 변경
                }}
              />
            ))}
          </div>
        )}
      </ColorConsumer>
      <hr />
    </div>
  );
};

export default SelectColors;

잘 바뀌는지 확인해보자!

profile
호떡 신문지에서 개발자로 환생

0개의 댓글