[React] Context

찐새·2022년 9월 6일
0

React

목록 보기
11/21
post-thumbnail

Context

모달을 구현하면서 props 전달을 최소화하고 싶었다. 컴포넌트가 한 단계 차이라면 상관없지만, 내가 원한 구현은 A 컴포넌트에서 버튼을 클릭하면 B 안에 있는 C 모달이 열리는 구조였다.

일반적이라면 A -> BstatesetState를 보내고, B -> CsetState를 보내야 한다. 얼마나 꼴뵈기 싫은가…

props drilling

고민하던 차에 책에서 봤던 Context가 생각났다. props를 전달하지 않고 해당 컴포넌트에서 직접 호출하기 위해 사용했다.

Context 생성

ContextReact 컴포넌트 트리 안에서 전역적(global)이라고 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법이다.

// modalOpen.js

import { createContext, useState } from "react";

const ModalOpen = createContext({
  state: { isOpen: false },
  actions: {
    setIsOpen: () => {},
  },
});

const ModalProvider = ({ children }) => {
  const [isOpen, setIsOpen] = useState(false);
  const value = {
    state: { isOpen },
    actions: {
      setIsOpen,
    },
  };
  return <ModalOpen.Provider value={value}>{children}</ModalOpen.Provider>;
};

const { Consumer: ModalConsumer } = ModalOpen;

export { ModalProvider, ModalConsumer };

export default ModalOpen;

먼저 모달의 현재 상태와 제어 함수가 담긴 context를 생성했다.

Context는 사용할 컴포넌트를 감싸는 provider와 사용하는 cunsumer가 필요하다. provider에서 context의 statesetState를 정의했다.

provider

// index.js

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { ModalProvider } from "./context/open";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <ModalProvider>
      <App />
    </ModalProvider>
  </React.StrictMode>
);

전역에서 사용할 수 있도록 <App /> 컴포넌트를 provider로 감쌌다.

useContext

차례차례 useContext를 호출하여 필요한 props만 사용했다.

// App.js

import { useContext } from "react";
import ModalOpen from "./context/open";
import Table from "./Table";

export default function App() {
  const {
    actions: { setIsOpen },
  } = useContext(ModalOpen);
  return (
    <div>
      <Table />
      <button onClick={() => setIsOpen(true)}>열기</button>
    </div>
  );
}

App 컴포넌트에서는 모달을 여는데 필요한 액션만 호출했다.

// Table.js

import { useContext } from "react";
import ModalOpen from "./context/open";
import Modal from "./Modal";

export default function Table() {
  const {
    state: { isOpen },
  } = useContext(ModalOpen);
  return (
    <div>
      <h3>Table</h3>
      {isOpen && <Modal />}
    </div>
  );
}

Table 컴포넌트에서는 모달을 여는 조건인 state만 호출했다.

import { useContext } from "react";
import styled from "styled-components";
import ModalOpen from "./context/open";

const Overview = styled.div`
  width: 100vw;
  height: 100vh;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.7);
`;

const Box = styled.div`
  width: 500px;
  height: 300px;
  background-color: white;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
`;

export default function Modal() {
  const {
    actions: { setIsOpen },
  } = useContext(ModalOpen);
  return (
    <Overview>
      <Box>
        <h1>hello!</h1>
        <button onClick={() => setIsOpen(false)}>닫기</button>
      </Box>
    </Overview>
  );
}

Modal 컴포넌트에서는 다시 닫아야 하므로 액션을 호출했다.

결론

멀리 떨어진 컴포넌트로의 props 전달이 싫어서 새로 배운 Context를 사용해 봤다. 더 좋은 방법이 있겠지? 더 고민해 보자.


참고
도서 - 『리액트를 다루는 기술』, 김민준(velopert), 길벗
React Dos - Context

profile
프론트엔드 개발자가 되고 싶다

0개의 댓글