Context API

윤건호·2023년 11월 1일
1

리액트,리덕스

목록 보기
8/9

Context API

리액트 컴포넌트간 어떠한 값을 전달할 때 사용하는 방법 중 하나입니다.

Props와 같이 어떠한 값을 전달해준다는 부분에선 비슷하다고 할 수 있습니다.

그럼 Context API 를 왜 사용하는걸까?

Context API 의 데이터 전달 방식 중 핵심은 필요한 컴포넌트에서 직접 접근해 값을 가져올 수 있다 라는 것 입니다.

Context API를 자세히 소개하기 전 Props의 값 전달 방식에 대해 먼저 말씀드리겠습니다.

제가 진행하는 프로젝트의 구조가 APP > A > B > C 와 같은 구조로 이루어져있고,

전역인 APP 에서 C 컴포넌트로 값을 전달해주고자 할 때, 해당 값과는 관련이 없는 A , B 컴포넌트에게 전달이 된 후 B의 하위인 C 컴포넌트에 전달하는게 Props를 사용하는 일반적인 구조입니다.

A,B 컴포넌트에선 값이 필요하지 않지만, 단순 하위 컴포넌트에 전달만을 위해
프롭으로 값을 받아와야 하는 상황이 발생하게 되는 것 입니다.

예를 든 구조가 간단해서 큰 어려움을 느끼지 못할 수 있지만, 조금 더 큰 프로젝트라면 불편함과 여러번 전달함과 수정함에 있어서 충분히 실수가 발생할 수 있는 부분입니다.

또 저와같은 초보 개발자라면, 본인이 짠 코드와 컴포넌트를 왔다갔다하다가
길을 잃어버리는 상황이 생길 수 있습니다.

위와 같은 상황이라면 Context 를 사용해 값을 전달해봄을 고려해볼만 합니다.

Context API 구성

"use client";
import React, { useContext } from "react";
import { createContext } from "react";

type Props = {
  children: React.ReactNode;
};

type LoginStateType = {
  isLogin: boolean;
  setIsLogin: React.Dispatch<React.SetStateAction<boolean>>;
};

const LoginStateContext = createContext<LoginStateType>({
  isLogin: false,
  setIsLogin: () => {},
});

export default function LoginContext({ children }: Props) {
  const [isLogin, setIsLogin] = React.useState(false);
  return (
    <LoginStateContext.Provider value={{ isLogin, setIsLogin }}>
      {children}
    </LoginStateContext.Provider>
  );
}

export const useLoginStateContext = () => useContext(LoginStateContext);

위와 같이 우리만의 Login State Context를 만들었습니다.

그럼 이제 코드를 하나하나 뜯어보겠습니다.

const LoginStateContext = createContext<LoginStateType>({
  isLogin: false,
  setIsLogin: () => {},
});

createContext 를 통해 Context 객체를 생성해 LoginStateContext 에 담아주고 있습니다.

createContext({
isLogin: false,
setIsLogin: () => {},
});

createContext의 defalutValue 값은 context 를 사용하는 트리 안에서 적절한 Provider를 찾지 못했을 때 사용되는 값입니다.

쉽게 말해 createContext 를 통해 context는 만들었지만,
Provider로 값은 전달하지 않은 채 다른 컴포넌트에서 useContext를 사용하게 되면 전달되는 값이라고 할 수 있습니다.

export const useLoginStateContext = () => useContext(LoginStateContext);

useContext는 컨텍스트 값을 읽어오기 위해 사용되는 react 훅입니다.

해당 훅을 사용하여 컨텍스트 값에 바로 접근할 수 있게 됩니다.

또 useLoginStateContext 라는 훅을 직접 만들어 export 하여 만들어두게 된다면, 해당 컨텍스트를 사용하는 쪽에서 매번 useContext 를 사용하여 값을 넣어주지 않고

const data = useLoginStateContext();

이런식으로 아주 간결하게 사용할 수 있으며 읽고 이해하기 쉽기 때문입니다.

쉽게 말해 저렇게 쓰는게 더 편하기 때문이라고 할 수 있습니다.

<LoginStateContext.Provider value={{ isLogin, setIsLogin }}>
{children}
</LoginStateContext.Provider>

Provider 컴포넌트는 value props를 받아서 이 값을 하위에 있는 컴포넌트에게 전달합니다.
값을 전달받을 수 있는 컴포넌트의 수에 제한은 없습니다.
Provider 하위에 또 다른 Provider를 배치하는 것도 가능하며, 이 경우 하위 Provider의 값이 우선시됩니다.

context api 와 props의 렌더링 차이

간단한 예시를 통해 차이를 알아보겠습니다.

이 예시에선 A > B > C 의 컴포넌트 구조를 사용하고 있으며,
전역에서 Context 를 전달하고 value에 count와 setCount를 넣어 전달해주고 있습니다.

이렇게 작고 귀여운 Context 를 만들어 C 컴포넌트에 직접 전달하였습니다.

간단하게 설명드리면 초기값 1로 시작해 set 함수를 통하여 count를 변경할 것이고, 그랬을 때 A와 B 컴포넌트의 렌더링 여부를 확인해볼 것입니다.

C 컴포넌트에서 CountValue 를 불러온 모습이고, 내부 구현을 통해
화면에 렌더링 + 버튼 클릭을 통해 값을 업데이트하는 코드를 구현했습니다.

여전히 C컴포넌트는 A > B > C 구조에서 최하위의 위치하는 컴포넌트이고,
각각의 컴포넌트에는 콘솔에 렌더링이 되었다 라는 코드를 작성해두었습니다.

이때 C 컴포넌트에 전달된 버튼을 눌러 값이 변한다면

와 같이 useContext 로 값을 전달한 C 컴포넌트만 렌더링이 되는 것을 볼 수 있습니다.

위와 같은 chat GPT의 답변을 직접 눈으로 확인한 순간입니다.

반면 Props을 통해 전달된 값이 바뀐다면 어떻게 될까요?

위와 같은 프로젝트 구조로 값을 변경해보겠습니다.

위와 같은 결과가 나오는 것을 볼 수 있습니다.

정리

Context API와 Props는 값을 단방향 구조로 전달할 수 있는 아주 유용한 기능입니다.

단지 렌더링의 횟수에 따라 Context API 가 좋다기엔 전역에서 상태를 관리함에 있어서는 특히 주의가 필요하기 때문에 각자 프로젝트의 색깔이나 구조에 맞게 선택해서 사용하는 것이 좋다고 생각합니다.

profile
더 배우고 싶은 프론트엔드 개발자 윤건호입니다.

2개의 댓글

comment-user-thumbnail
2023년 11월 4일

이해가 쏙쏙 되네요~ 초보 개발자 맞으신지 의문이 듭니다^^ 항상 응원할게요!!

1개의 답글