[React] Context API 파헤치기

남다은·2023년 12월 31일
0

React

목록 보기
2/8
post-thumbnail

Context API가 뭔지 본격적으로 알아보기 전에 상태 관리부터 알아보자!

🐵 상태

🧐 상태 관리가 왜 필요할까?

이 질문에 답하기 전에 '상태'가 뭔지 정의해보자.

웹 어플리케이션에서 상태로 분류될 수 있는 것들은 다음과 같다.

1. UI에서의 상태

  • 기본적으로 웹 애플리케이션에서 상태를 의미하며, 상호 작용이 가능한 모든 요소의 현재 값을 의미한다.

2. URL에서의 상태

3. 폼(Form)에서의 상태

  • 폼에서는 로딩 중인지(loading), 현재 제출됐는지(submit), 접근이 불가능한지(disabled), 값이 유효한지(validation) 등의 상태가 존재한다.

4. 서버에서 가져온 값의 상태

  • 클라이언트에서 서버로 요청을 통해 가져온 값도 상태로 볼 수 있다. 대표적으로 API 요청을 들 수 있다.

이와 같은 상태가 애플리케이션에 존재할 때, 전체적으로 관리해야 할 상태가 있다고 가정해보면 그 상태에 따라 다양한 요소들이 알맞은 UI를 보여줘야 한다.
상태가 유효한 범위를 제한하고, 상태의 변화에 따라 변경되어야 하는 자식 요소들이 상태 변화를 어떻게 감지할지 등 다양한 상태 관리가 필요해짐에 따라 현대 웹 애플리케이션에서는 이러한 상태를 효율적으로 관리하고, 상태가 필요한 쪽에 빠르게 반응할 수 있도록 변화되었다.


🔱 Props Drilling?

  • 부모에 있는 상태를 자식 컴포넌트에 쓰기 위해서 props를 내려주는 방식을 의미한다.

✨ Props Drilling 장점

  • 명시적인 값을 사용함으로써 각 컴포넌트에서 어떤 프로퍼티를 받아서 사용하는지 명확하게 파악할 수 있다.
  • 값의 흐름을 쉽게 추적할 수 있다. -> 디버깅 할 때 편리해진다.
  • 데이터가 전달되는 경로를 알 수 있기 때문에 코드 변경이 애플리케이션의 다른 부분에 어떤 영향을 주는지 파악하는데 용이하다.

🤧 Props Drilling 단점
-> 자식 컴포넌트의 깊이가 깊어질수록 발생한다!

  • 데이터의 형식을 변경해야 하는 경우 컴포넌트 계층 전체에서 업데이트 하는 것이 번거롭다.
  • 컴포넌트 분리 과정에서 중간 컴포넌트를 통해 불필요한 프로퍼티가 전달될 수 있어서 불필요한 복잡성을 초래한다.
  • 누락된 프로퍼티를 인지하기 어렵다.
  • 프로퍼티 이름이 변경되면 해당 값을 추적해서 업데이트하는 것이 어려워진다.
  • props drilling의 단점을 해소하고자 리액트에서 전역 상태를 하위 컴포넌트에 주입할 수 있는 새로운 Context API를 출시했다!
  • Context API를 사용함으로써 props로 상태를 넘겨주지 않더라도 원하는 곳에서 Context Provider가 주입하는 상태를 사용할 수 있게 되었다. 🤩

Context API

🧐 Context API 왜 쓸까?

  • 앞서 설명한 것처럼 React 애플리케이션에서는 부모로부터 자식으로 데이터가 props로 전달되지만 애플리케이션 안의 여러 컴포넌트들에게 전달해야하는 props의 경우 이런 과정이 번거로울 수 있다.
  • context를 사용하게되면 트리 단계마다 명시적으로 props를 넘겨주지 않아도 컴포넌트가 이 값들을 공유하도록 할 수 있다!

🧐 Context API, 언제 써야할까?

  • context는 React 컴포넌트 트리 안에서 전역(global)으로 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법이므로, 그러한 데이터를 다룰 때 사용한다.
  • 예시로는 현재 로그인한 유저, 테마, 선호하는 언어 등이 있다.

🧐 Context API, 어떻게 써야할까?

👛 React.createContext

const MyContext = React.createContext(defaultValue);
  • Context 객체를 만든다.
  • React는 Context 객체를 갖고 있는 컴포넌트를 렌더링할 때 트리 상위에서 가장 가까이에 있는 짝이 맞는 Provider로부터 현재 값을 읽는다.

👛 Context.provider

<MyContext.Provider value={/* 어떤 값 */}>
  • Context 객체에 포함된 React 컴포넌트인 Provider는 context를 구독하는 컴포넌트들에게 context의 변화를 알리는 역할을 한다.
  • provider를 전달하는 변수는 꼭 value를 사용해야 하며 value prop을 받아서 해당 값을 하위의 컴포넌트에게 전달한다. (전달 받는 컴포넌트의 수는 제한되지 않는다.)
  • Provider 하위에서 context를 가진 컴포넌트는 provider의 value를 가진 state가 변화할 때마다 전부 re-render된다.

👛 Context.Consumer

<MyContext.Consumer>
  {value => /* context 값을 이용한 렌더링 */}
</MyContext.Consumer>
  • context 변화를 구독하는 React 컴포넌트이다.
  • Context.Consumer 컴포넌트를 사용하면 함수 컴포넌트 안에서 context를 구독할 수 있다.
  • Context.Consumer의 자식은 함수(컴포넌트)여야 한다.
  • consumer 컴포넌트가 가지는 context 값은 가장 가까운 provider의 값이다. 만약 상위 provider가 없는 경우에는 createContext()에서 정의한 defaultValue를 갖는다.

더 자세한 내용은 공식문서, 공식문서2


🤧 Context API 단점

  • Provider Hell
  • 별도의 컨벤션이 없다
  • Context를 사용하게되면 Provider 내에 있어야 하고, 상위 컴포넌트 내부에 있어야 한다는 제약이 있기 때문에 컴포넌트를 재사용하기가 매우 힘들어진다
  • 최상단의 state를 업데이트하면 하위의 컴포넌트가 모두 리렌더링되어 성능 문제가 있다.

👻 useContext

공식문서

  • useContextContext API에서 제공된 데이터를 쉽게 읽어올 수 있도록 도와주는 React Hook이다.
  • 즉 useContext !== Context API
const value = useContext(SomeContext)

✨ useContext 장점 - 왜 쓸까?

  • 전역 상태 관리를 간편하게 할 수 있다.
  • Provider와 Consumer를 직접 사용하기보다 훅을 사용함으로써 더 간결하고 직관적인 코드를 작성할 수 있다.
  • 여러 Context를 사용하는 경우에도 간편하게 상태를 관리할 수 있다.

사용법

import { useContext } from 'react';

function Button() {
  const theme = useContext(ThemeContext);
  // ...
  • useContext는 전달한 context에 대한 context값을 반환한다.
  • React는 컴포넌트 트리를 탐색하여 특정 컨텍스트에 대해 위에서 가장 가까운 컨텍스트 Provider를 찾는다.

profile
주저리주저리 생각 정리

0개의 댓글