[MGS 3기 - 35일차] Context API

박철연·2022년 5월 31일
0

MGS STFE 3기

목록 보기
32/35

진상현 강사님의 수업에서 실습을 통해 Context API에 대해 복습했습니다. Context API에 대한 내용을 간단히 언급만 하고 넘어간 것 같아 독립된 포스팅으로 정리해보았습니다.

Context API 소개

Context API의 개념

React에서 컴포넌트가 데이터를 다루는 방법에는 Props, State 그리고 Context가 있습니다. 그 중 Props와 State에 대해서는 다른 글에서 다루었고, 이 글에서는 Context에 관한 개념만 정리하겠습니다.

이미 학습한 props는 단방향으로만 데이터가 흐릅니다. 부모에서 자식 컴포넌트로만 props 내의 데이터가 흐르죠.

그러다보니, 현재 작업중이 아닌 컴포넌트로 흘러간 (즉, 흘러간 갈래가 다른) props를 사용하려면 유일한 방법은 공통된 부모에 해당 데이터를 넣어주는 것 뿐입니다.

리액트에서는 이러한 문제를 해결하기 위해 Flux라는 개념을 도입하였고, 이를 사용하는 것이 Context API입니다.

즉, Context API는 props의 흐름과 상관없이 전역적으로 사용될 데이터를 다룰 때 매우 유용하게 작용합니다.

Context API의 원리

Context API를 사용하기 위해서는 Provider와 Consumer의 개념을 사용해야 합니다.

먼저 공통적으로 가지는 부모 컴포넌트에 실제 데이터를 주입할 Provider를 작성합니다. (위 이미지의 경우에는 최상단의 Root Component일 것입니다.)

그런 다음, 해당 데이터를 사용할 자식 컴포넌트에 Consumer를 작성하여 데이터를 불러옵니다.

Context API의 장단점

Context API는 위에서 언급한 Provider와 Consumer의 개념만 알면 쉽게 프로젝트에 적용할 수 있습니다.

반면에 상태 관리 라이브러리의 대표 주자인 Redux 같은 경우에는 전역 store에서 데이터를 받고 다시 필요한 곳에 뿌리는 코드가 매우 복잡하고, 이로 인해 높은 진입 장벽이 있다고 평가되는 부분이 있습니다.

따라서 Context API는 많은 투자를 하지 않고도 간편하게 리액트 프로젝트 내에서 상태를 관리할 수 있습니다.

반면에, Context API는 단점도 가지고 있습니다. 아래 코드 예시로 설명해보겠습니다.

const App = () => {
  return (
    <ModalProvider>
      <ModalToggleButton />
      <Modal />
    </ModalProvider>
  )
}

const ModalToggleButton = () => {
  const [, setShow] = useContext(ModalContext);
  
  return <button onClick={() => setShow((state) => !state)}>모달토글</button>;
}

const Modal = () => {
  const [show] = useContext(ModalContext);
  
  return show ? <div>나 모달</div> : null;
}

현재 위 코드는 useContext 훅을 사용하여 show라는 상태를 사용하는 중입니다.

자세히 보시면, ModalToggleButton이라는 자식 컴포넌트가 있는데, 이 컴포넌트는 show라는 데이터를 직접 사용하지는 않고, 오로지 show의 setter 함수만 사용하고 있는 것을 확인할 수 있습니다.

그런데 Context API는 show를 사용하지 않더라도, show가 변경되면 useContext를 사용하는 모든 컴포넌트까지 다시 렌더링합니다.

show를 사용하는 Modal만 재렌더링되는 것이 아니라, ModalToggleButton까지 같이 재렌더링되는 것입니다.

이는 코드 실행에 있어 비효율을 초래할 뿐만 아니라, 특정 요구 사항을 충족하지 못하는 결과를 낳을 수도 있습니다.

이를 해결하기 위해서는, 상태값과 함수를 분리하여 Provider로 감싸줘야 합니다. 물론 이는 코드가 지나치게 길어지고, 유지 보수에 비효율을 초래합니다.

뿐만 아니라, Context API를 사용하면 컴포넌트가 외부의 데이터를 받아오기 때문에 재사용이 까다로워집니다. (이는 Context API 뿐만 아니라 모든 상태 관리 라이브러리들이 공통적으로 가지는 단점입니다.)

재사용도 힘들어지는데다가, 외부의 데이터를 대신한 mocking 데이터가 있어야 단위 테스트를 진행할 수 있습니다.

따라서 Context API를 사용하기 전에, 컴포넌트가 재사용될 상황을 고려하고, 재사용이 빈번하게 일어날 케이스라면 컴포넌트 합성을 고려하는 것이 더 효과적일 수 있습니다.

Context API 사용해보기

위에서 설명한 Provider와 Consumer의 개념을 가지고 코드를 보는 것이 효과적입니다.

import { createContext, useContext } from "react";
const defaultName = 'asdf';
const NameContext = createContext(defaultName);

const Hello1 = () => {
const name = useContext(NameContext);
return (
	<div>
		this is Hello1. and Name is {name}
		<Hello4 />
	</div>
	);
};

const Hello4 = () => {
const name = useContext(NameContext);
return (
	<div>
		this is Hello4
		<div>Hello {name}!</div>
	</div>
);
};
const App = () => (
	<NameContext.Provider value={defaultName} >
		<Hello1 />
	</NameContext.Provider>
);
export default App;

createContext를 통해 전역 상태 선언해주는 것이 첫번째입니다.

그러고 나면, Context.Provider 안쪽에 렌더된 컴포넌트들은 useContext 훅을 통해 context의 value에 접근 가능해지게 됩니다.

profile
Frontend Developer

0개의 댓글