본문 바로가기

React

[React] Redux: App-Wide State와 Cross-Component State 관리 가이드

 

1. Redux 상태 관리의 기본 개념

 

client state( 웹 브라우저 세션과 관련된 모든 정보)  는 사용 범위에 따라 3가지로 나뉩니다

 

1. local state 

2. cross-component state

3. app-wide state

 

 

1.1. Local State (지역 상태) 


단일 컴포넌트 내에서만 사용되는 상태
useState, useReducer 훅을 사용하여 관리

 

  • 폼 입력 상태
  • 토글 상태 (열기/닫기) 
  • UI 상태
function Component() {
  const [isVisible, setIsVisible] = useState(false);
  // 이 상태는 이 컴포넌트 내에서만 사용됨
}

 

 

1.2. Cross-Component State (교차 컴포넌트 상태) 


여러 컴포넌트 간에 공유되는 상태( 주로 형제 컴포넌트 )
주로 props drilling이나 컨텍스트(Context Api), 혹은 Redux 를 통해 관리

 

  • 모달 상태
  • 특정 기능에 관련된 데이터
  • 제한된 범위의 컴포넌트 간 공유 데이터
// Context 생성
const ThemeContext = React.createContext();

// 부모 컴포넌트
function Parent() {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Child />
    </ThemeContext.Provider>
  );
}

 

  // 예: 모달 상태 공유
  const ModalContext = React.createContext({
    isOpen: false,
    toggleModal: () => {}
  });

 

 

1.3. App-Wide State (애플리케이션 전역 상태)


전체 애플리케이션에서 사용되는 상태
Context API나 Redux 같은 상태 관리 라이브러리로 관리

 

  • 사용자 인증 정보
  • 장바구니 데이터
  • 테마 설정
  • 전역 설정 등..
const CartContext = React.createContext({
  items: [],
  addItem: () => {},
  clearCart: () => {}
});

// 애플리케이션 전체에서 사용 가능
function App() {
  return (
    <CartContext.Provider value={cartState}>
      <AppContent />
    </CartContext.Provider>
  );
}

 

 

2. Redux 사용이 필요한 경우

 

2.1 Cross-Component State

 

Context api 대신 redux 를 고려해야 할만한 상황은?

(단 둘다 중복으로 사용도 가능합니다. )

 

- 복잡한 컴포넌트 트리 구조인 경우

- 빈번한 상태 업데이트을 할 경우 

 

- 복잡한 상태 로직

 

- 상태 변화의 추적이 필요한 경우

  // store/slices/cartSlice.js
  const cartSlice = createSlice({
    name: 'cart',
    initialState: {
      items: [],
      totalAmount: 0
    },
    reducers: {
      addItem(state, action) {
        const newItem = action.payload;
        const existingItem = state.items.find(item => item.id === newItem.id);
        if (existingItem) {
          existingItem.quantity++;
        } else {
          state.items.push({ ...newItem, quantity: 1 });
        }
        state.totalAmount = state.items.reduce((total, item) => 
          total + (item.price * item.quantity), 0);
      }
    }
  });

 


- 다수의 컴포넌트가 동일 데이터 참조할 경우

  // Redux 사용 예시
  const ProductList = () => {
    const products = useSelector(state => state.products.items);
    const dispatch = useDispatch();
    
    const addToCart = (product) => {
      dispatch({ type: 'ADD_TO_CART', payload: product });
    };
  };

 

 

 

2.2 App-Wide State

 

사용예시)

  // store/slices/authSlice.js
  const authSlice = createSlice({
    name: 'auth',
    initialState: {
      isLoggedIn: false,
      user: null,
      token: null
    },
    reducers: {
      login(state, action) {
        state.isLoggedIn = true;
        state.user = action.payload.user;
        state.token = action.payload.token;
      },
      logout(state) {
        state.isLoggedIn = false;
        state.user = null;
        state.token = null;
      }
    }
  });