Context API가 상태관리 라이브러리의 대안이 될 수 없는 이유

Seju·2024년 4월 3일
0

React

목록 보기
9/9
post-thumbnail

Context API란?


ContextAPI는 React 웹 애플리케이션 개발 시 컴포넌트 트리 내부에서 데이터들을 전역적으로 공유할 수 있는 방법을 제공하는 방법입니다.

  • 이는 주로 컴포넌트의 깊이가 깊어질때, 상위 컴포넌트에서 하위 컴포넌트로 props를 단계별로 전달하는 Props Drilling을 해결하기 위해 사용됩니다.
  • Context를 통해, 중간에 있는 여러 컴포넌트를 거치지 않고도, 컴포넌트 트리 깊은 곳에 있는 컴포넌트에 데이터를 전달할 수 있게 됩니다.


그럼에도 불구하고 Context API는 전역상태 관리 라이브러리의 대안이 아니다.

전역 상태관리 라이브러리 Redux,Zustand등과 같이 store 내부에 상태나 데이터를 정의하고, Props Drilling 없이 전역적으로 상태를 참조하고, 사용할 수 있다는 관점에선 동일한 역할을 지닙니다.

  • 그럼에도 불구하고 Context API는 전역 상태 관리 라이브러리의 대안이 될 수 없습니다. 왜일까요?

1. Context API 사용시, 구독하는 모든 컴포넌트들에 대한 리렌더링이 발생한다.

Context API를 사용할때, 해당 컨텍스트를 구독하는 모든 컴포넌트들은 상태변화와 상관없이 모두 리렌더링이 발생합니다.

  • 이를 증명하기 위해 Context API로 간단한 유저상태를 구현하겠습니다.

  • 먼저 UserContext라는 파일을 생성한후, 해당 Context를 전역적으로 공급하기 위한 간단한 코드를 작성했습니다.

    • UserContext엔 users의 초기상태를 나타내는 initalUsersProfile와, users의 상태를 변경하는 함수인 setUser를 내보냈습니다.

/* 📑 UserContext.jsx */

import {createContext, useState} from "react";

/* Context 기본값 설정 */
const initalUsersProfile = {
  name: "Seju",
  posts: [
    "Context API가 상태관리 라이브러리의 대안이 될 수 없는 이유",
    "Babel 왜쓰고 왜 사용할까?",
  ],
};

export const UserContext = createContext({
  user: initalUsersProfile,
  setUser: () => {},
});


/* Provider로 전역적으로 상태를 공급. */
const UserProvider = ({children}) => {
  const [user, setUser] = useState(initalUsersProfile);

  return (
    <UserContext.Provider value={{user, setUser}}>
      {children}
    </UserContext.Provider>
  );
};

export default UserProvider;
  • 이후 Main.jsx에서 구성한 UseProvider 함수를 공급합니다.
  • context를 사용하는 <UserProfile>컴포넌트와 context와는 연관이 없는, 정적인 JSX를 가지고 있는 <UserPosts> 컴포넌트를 생성했습니다.

main.jsx


Context를 사용하는 UserProfile 컴포넌트

/* 📑 UserProfile.jsx */


import {useContext} from "react";
import {UserContext} from "../context/UserContext";

function UserProfile() {
  const {user} = useContext(UserContext);

  console.log("UserProfile 컴포넌트 리렌더링 발생");

  return (
    <>
      <div>{user.name}</div>
    </>
  );
}

export default UserProfile;

Context와 연관이 없는 UserPost 컴포넌트

/* 📑 UserPosts.jsx */

function UserPosts() {
  console.log("UserPost 컴포넌트 리렌더링 발생");
  return (
    <>
      <div>Some Static Content</div>
    </>
  );
}

export default UserPosts;

해당 컴포넌트 두개를 전부 렌더링하고 있는 App.jsx

  • 마지막으로 App.jsx에서 유저상태를 변경하는 setUser 함수를 가져오고,
  • 이름변경 버튼 클릭 시 유저의 이름이 변경되도록 로직을 구성했습니다.
/* 📑 App.jsx */

function App() {
  const {setUser} = useContext(UserContext);

  const handleChangeUserName = () => {
    setUser((prevUser) => ({
      ...prevUser,
      name: "suwan",
    }));
  };

  return (
    <>
      <UserProfile />
      <UserPosts />
      <button onClick={handleChangeUserName}>이름변경</button>
    </>
  );
}

export default App;

이제 버튼 클릭시 어떤 user의 상태가 변경되어 리렌더링이 발생하게 됩니다. 어떤 컴포넌트들이 리렌더링이 발생할까요?

  • Context와는 전혀 상관없는 정적인 컴포넌트인 UserPosts 컴포넌트에서도 리렌더링이 발생하고 있습니다.
    • 이는 Context를 구독여부에 상관없이 Provider로 래핑된 컴포넌트는 상태가 변화될 때 모두 리렌더링이 발생함을 의미합니다.
    • 따라서 변경된 값이 실제로 필요로 하지 않는 컴포넌트들 까지도 불필요하게 리렌더링이 발생합니다.

2. Context 변경에 따른 성능 최적화의 부재

이는 1번째 문제와 연관이 있습니다.

  • 컨텍스트를 구독하는 모든 컴포넌트가 컨텍스트의 값이 변경될 때마다 리렌더링이 발생한다는 점입니다.
  • Context API는 컨텍스트 내 특정한 값의 변경에만 반응하는것과 같이 세밀한 업데이트 제어를 제공하고 있지않습니다.
    • 이는 특히 애플리케이션의 규모가 커질수록 불필요한 리렌더링으로 이어질 수 있고, 성능저하의 원인이 될 수 있습니다.

이에 반해 전역상태관리 라이브러리는?

  • 반면 전역상태관리 라이브러리는 성능최적화에 관련해 더 많은 기능과 제어를 제공하고 있습니다.
    • 이러한 라이브러리는 보통 애플리케이션의 상태를 store에 저장하고, 컴포넌트는 스토어의 특정부분을 구독할 수 있도록 설계되었습니다.
    • 컴포넌트는 필요한 상태에 일부분만을 선택적으로 구독할 수 있고, 구독한 상태부분이 변경될때만 리렌더링이 발생합니다(구독한 상태를 사용하지 않는 컴포넌트는 불필요하게 리렌더링이 발생하지 않습니다.)

3. Context API는 애초에 전역 상태를 관리하기 위한 목적으로 설계되지 않았다.

https://github.com/facebook/react/issues/14110 에서 리액트 팀원이였던 Sebastian Markbåge가 작성한 댓글을 발췌 했습니다.

해당 댓글은 React의 Context API에 대한 사용 사례와 한계를 설명하고 있습니다. 해당 내용에 핵심부분을 번역하면,

  • 낮은 빈도의 변경에 적합하다.
    • Context API는 변경사항이 드물게 발생하는 경우에 적합하다고 언급하고 있습니다.
    • 예를들어, 애플리케이션의 테마설정등과 같은 사용자가 애플리케이션을 사용하는 동안 자주 바뀌지 않는 값들을 의미합니다.
  • 상태관리 라이브러리의 대체제로는 부적합하다.
    • Context API는 애플리케이션의 상태를 중앙에서 관리하고, 상태변화를 일관되게 처리하는 전역상태관리라이브러리등과 다르게, 이러한 용도보다는 상대적으로 단순하고, 변화가 드문 전역 데이터를 공유하는것에 더 적합하다는 점을 강조하고 있습니다.

결론을 요약하자면 Context API는 특정 유형(값이 자주바뀌지 않는 정적인 유형)의 상태관리에서는 선택적으로 사용될 수 있지만, 복잡한 상태관리 요구사항을 가진 애플리케이션은 다른 상태관리 솔루션을 고려해야한다는 점을 설명하고 있습니다.

profile
Talk is cheap. Show me the code.

0개의 댓글