Frameworks/React

React 상태 관리

newclass 2025. 4. 1. 00:41

React 상태 관리 - Context API와 Redux

상태 관리의 필요성

React 애플리케이션이 커지고 복잡해질수록 컴포넌트 간 데이터 공유와 상태 관리는 중요한 과제가 됩니다. 간단한 애플리케이션에서는 props를 통해 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 방식이 충분할 수 있지만, 컴포넌트 트리가 깊어지면 다음과 같은 문제가 발생합니다:

  1. Props 드릴링(Prop Drilling): 여러 계층의 컴포넌트를 통해 데이터를 전달해야 할 때 발생하는 코드 복잡성
  2. 상태 동기화: 여러 컴포넌트에서 동일한 상태를 사용할 때 일관성 유지 문제
  3. 코드 유지보수: 상태 로직이 여러 컴포넌트에 분산될 때 발생하는 유지보수 어려움

이러한 문제를 해결하기 위해 다양한 상태 관리 기법과 라이브러리가 등장했으며, 그 중 가장 많이 사용되는 것이 React의 Context API와 Redux입니다.

React Context API

Context API는 React에 내장된 기능으로, 컴포넌트 트리 전체에 데이터를 제공할 수 있는 방법을 제공합니다.

Context API의 주요 개념

  1. Context: 공유할 데이터를 저장하는 객체
  2. Provider: Context 값을 하위 컴포넌트에 제공하는 컴포넌트
  3. Consumer: Context 값을 사용하는 컴포넌트 (현대 React에서는 주로 useContext 훅 사용)

Context API 사용 방법

1. Context 생성

// UserContext.js
import React, { createContext, useState } from 'react';

// Context 생성
export const UserContext = createContext(null);

// Provider 컴포넌트
export function UserProvider({ children }) {
  const [user, setUser] = useState(null);

  // 로그인 함수
  const login = (userData) => {
    setUser(userData);
  };

  // 로그아웃 함수
  const logout = () => {
    setUser(null);
  };

  // Provider를 통해 값과 함수 제공
  return (
    <UserContext.Provider value={{ user, login, logout }}>
      {children}
    </UserContext.Provider>
  );
}

2. Provider로 애플리케이션 감싸기

// App.js
import React from 'react';
import { UserProvider } from './UserContext';
import Dashboard from './components/Dashboard';
import LoginPage from './components/LoginPage';

function App() {
  return (
    <UserProvider>
      <div className="app">
        <h1>My Application</h1>
        <LoginPage />
        <Dashboard />
      </div>
    </UserProvider>
  );
}

export default App;

3. Context 값 사용하기

// LoginPage.js
import React, { useState, useContext } from 'react';
import { UserContext } from '../UserContext';

function LoginPage() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const { user, login } = useContext(UserContext);

  const handleSubmit = (e) => {
    e.preventDefault();
    login({ username });
  };

  if (user) {
    return <p>이미 로그인되었습니다, {user.username}님!</p>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <h2>로그인</h2>
      <input
        type="text"
        placeholder="사용자명"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input
        type="password"
        placeholder="비밀번호"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">로그인</button>
    </form>
  );
}

export default LoginPage;
// Dashboard.js
import React, { useContext } from 'react';
import { UserContext } from '../UserContext';

function Dashboard() {
  const { user, logout } = useContext(UserContext);

  if (!user) {
    return <p>대시보드를 보려면 로그인하세요.</p>;
  }

  return (
    <div>
      <h2>대시보드</h2>
      <p>안녕하세요, {user.username}님!</p>
      <button onClick={logout}>로그아웃</button>
    </div>
  );
}

export default Dashboard;

Context API의 장점과 한계

장점:

  • React에 내장되어 있어 추가 라이브러리 불필요
  • 간단한 설정으로 전역 상태 관리 가능
  • 컴포넌트 트리 어디서나 상태에 접근 가능

한계:

  • 복잡한 상태 로직에는 관리가 어려울 수 있음
  • 상태 변경의 추적과 디버깅이 어려울 수 있음
  • 잦은 렌더링 최적화 필요
  • 여러 Context를 사용할 때 Provider 중첩 문제