[React] 전역 상태 관리 (1) - Props Drilling

박하늘·2025년 2월 24일

React

목록 보기
9/15
post-thumbnail

[전역 상태 관리]

1️⃣ 정의

  • 애플리케이션 내에서 여러 컴포넌트가 공유해야 하는 상태(state)를 중앙에서 한곳에 모아 관리하는 방법을 의미
  • React에서는 기본적으로 useState나 useReducer를 사용하여 개별 컴포넌트 내에서 상태를 관리하지만, 여러 컴포넌트가 동일한 데이터를 필요로 할 경우 전역 상태 관리가 필요해집니다.

2️⃣ 필요성

1) Props Drilling 해결하여 가독성 향상

  • 부모 → 자식 → 손자 컴포넌트로 props를 전달하는 과정(Props Drilling)이 복잡해질 경우, 전역 상태를 사용하면 중간 컴포넌트에서 불필요한 데이터 전달을 줄일 수 있다.

2) 여러 컴포넌트에서 상태 공유

  • 예를 들어, 로그인 정보, 다크 모드 설정, 장바구니 데이터와 같이 여러 컴포넌트에서 공통적으로 사용해야 하는 데이터를 효율적으로 관리할 수 있습니다.

3) 일관된 상태 관리 가능

  • 전역 상태를 한 곳에서 관리하면 상태의 변경 흐름을 추적하기 쉬워지고, 예측 가능한 애플리케이션을 만들 수 있다.

4) 코드 유지보수성 향상

  • 로컬 상태를 여러 곳에서 따로 관리하면 코드가 복잡해질 수 있지만, 전역 상태를 도입하면 보다 구조적인 개발이 가능

3️⃣ 내/외부 관리 방법

[내부]

  • useState, useReducer, useContext

    • useState : 컴포넌트 내부에서 로컬 상태를 관리하는 기본적인 방법
    • useReducer : 복잡한 상태 로직을 다룰 때 사용하며, Redux와 유사한 패턴을 가짐
    • useContext : 전역적으로 상태를 공유하는 방법으로, 여러 컴포넌트에서 동일한 데이터를 접근할 수 있도록 함

  • context API

    • React에서 제공하는 내장 기능으로, Props Drilling 없이 전역 상태를 관리할 수 있도록 도와줍니다. createContext와 useContext를 사용하여 데이터를 공유할 수 있으며, 비교적 간단한 프로젝트에서 전역 상태를 관리하는 데 유용합니다.

[외부]

  • Redux,Rdux Toolkit
    • Redux : Flux 아키텍처 기반의 상태 관리 라이브러리로, 단일 상태 저장소(Store)를 통해 상태를 중앙에서 관리
    • Redux Toolkit : Redux의 사용성을 개선한 공식 라이브러리로, 보일러플레이트(반복 코드)를 줄이고 효율적인 상태 관리를 제공
  • Recoil, MobX, Zustand, Jotai
  • ect ...



⚛️ props drilling 이란 ?

컴포넌트 트리에서 최상위 컴포넌트의 데이터를 하위 컴포넌트로 전달할 때, 여러 단계를 거쳐야 하는 현상
React로 개발하다 보면 발생하는 자연스러운 현상

[예제]

import { useState } from "react";
import styled from "styled-components";

const Component = styled.div`
  font-weight: 700; border: 3px solid blue; border-radius: 10px; flex-grow: 1;
  line-height: 30px; text-align: center; padding: 10px; margin: 10px;
  > button {
    margin-left: 10px;
  }
`;

const Container = styled.div`
  display: flex; width: 100%; justify-content: center;
`;

export default function App() {
  const [count, setCount] = useState(0);

  console.log("App");
  return (
    <Container>
      <Component>
        App
        <Container>
          <Child1 count={count}/>
          <Child2 count={count} setCount={setCount} />
        </Container>
      </Component>
    </Container>
  );
}

function Child1({count}) {
  console.log("Child1");
  return (
    <Component>
      Child1
      <Container>
        <Child3 count={count}/>
        <Child4 />
      </Container>
    </Component>
  );
}

function Child2({count, setCount}) {
  console.log("Child2");
  return (
    <Component>
      Child2
      <Container>
        <Child5 />
        <Child6 count={count} setCount={setCount} />
      </Container>
    </Component>
  );
}

function Child3({count}) {
  console.log("Child3");
  return <Component>Child3 : {count}</Component>;
}

function Child4() {
  console.log("Child4");
  return <Component>Child4</Component>;
}

function Child5() {
  console.log("Child5");
  return <Component>Child5</Component>;
}

function Child6({count, setCount}) {
  console.log("Child6");
  return (
    <Component>
      Child6
      <button onClick={() => setCount(count + 1)}>+</button>
    </Component>
  );
}

🖥️ 실행 화면

  • <Child3\> 컴포넌트에서 <App\> 컴포넌트의 count 를 받아오려면 App → Child1 → Child3 순서로 전달
  • <Child6\> 컴포넌트에서 <App\> 컴포넌트의 count, setCount 를 받아오려면 App → Child2 → Child6 순서로 전달
  • 중간 컴포넌트인 <Child1\> , <Child2\> 는 해당 상태를 직접 사용하지 않지만, 단순히 props를 넘겨주는 역할만 수행
  • <Child6> 컴포넌트에 있는 onClick 실행 시 모든 컴포넌트가 리렌더링되며 불필요한 리렌더링 발생
  • 컴포넌트가 깊어질수록 이런 props 전달 과정이 반복되면서 코드가 복잡해지고 유지보수가 어려워집니다.

⚛️ props drilling의 문제점

1. 불필요한 코드 증가

  • 중간 컴포넌트가 직접 데이터를 사용하지 않아도, props를 계속해서 전달해야 함

2. 유지보수 어려움

  • 새로운 데이터를 추가하거나 수정할 때, 중간 컴포넌트들의 코드도 변경해야 함

3. 성능 저하 가능성

  • 불필요한 리렌더링이 발생할 수 있음

⚛️ 결론

  • 여러 컴포넌트에서 상태를 사용해야 할 때 === 전역 상태 관리가 필요할 때
  • 사용할 수 있는 도구가 필요해짐 => Context API, Redux, Redux Toolkit

0개의 댓글