Web

Modal Slice 활용하여, 모달 기능 추가

sungjae0309 2026. 5. 30. 00:10

저번 실습에서는 장바구니 데이터를 Redux Toolkit으로 관리했다. 여기서 한 단계 더 나아가, 장바구니 데이터뿐만 아니라 모달의 열림/닫힘 상태도 Redux Toolkit으로 관리하도록 기능을 추가했다. 

1. Modal Slice 생성

먼저 features/modal/modalSlice.ts 파일을 새로 만들었다.

모달 상태는 단순하게 isOpen 값 하나로 관리했다.

 
interface ModalState {
  isOpen: boolean
}

const initialState: ModalState = {
  isOpen: false,
}

 

 

 

const modalSlice = createSlice({
  name: 'modal',
  initialState,
  reducers: {
    openModal: (state) => {
      state.isOpen = true
    },
    closeModal: (state) => {
      state.isOpen = false
    },
  },
})

그리고 모달을 열고 닫는 reducer를 만들었다. 이렇게 하면 컴포넌트에서 dispatch(openModal()), dispatch(closeModal())을 호출하는 방식으로 모달 상태를 변경할 수 있다.

2. Store에 modal reducer 등록

새로 만든 modalSlice를 사용하려면 Store에도 reducer를 등록해야 한다.

export const store = configureStore({
  reducer: {
    cart: cartReducer,
    modal: modalReducer,
  },
})

이제 Redux Store는 장바구니 상태와 모달 상태를 함께 관리한다.

3. 전체 삭제 버튼 동작 변경

기존에는 전체 삭제 버튼을 누르면 바로 clearCart()가 실행됐다.

<button
  type="button"
  disabled={cartItems.length === 0}
  onClick={() => dispatch(openModal())}
>
  전체 삭제
</button>

하지만 여기선 바로 삭제하지 않고, 먼저 모달을 열도록 변경했다.

<button
  type="button"
  disabled={cartItems.length === 0}
  onClick={() => dispatch(openModal())}
>
  전체 삭제
</button>

 

4. Modal 컴포넌트 구현

모달 UI는 components/Modal.tsx 파일로 분리했다.

모달에는 두 개의 버튼이 있다.

  • 아니요: 모달만 닫기
  • : 장바구니 전체 삭제 후 모달 닫기
const handleConfirm = () => {
  dispatch(clearCart())
  dispatch(closeModal())
}

 

버튼을 눌렀을 때는 기존 미션 1에서 만든 clearCart() 액션을 그대로 재사용했다.
그리고 삭제가 끝난 뒤에는 closeModal()을 함께 실행해서 모달도 닫히도록 했다.

 
<button onClick={() => dispatch(closeModal())}>
  아니요
</button>

<button onClick={handleConfirm}>
  네
</button>

이 구조 덕분에 cart 관련 로직과 modal 관련 로직을 각각의 Slice에서 분리해서 관리할 수 있었다.

5. 모달 조건부 렌더링

App.tsx에서는 Redux Store에서 isOpen 값을 가져와 모달을 조건부 렌더링했다.

 
const { isOpen } = useAppSelector((state) => state.modal)

그리고 isOpentrue일 때만 모달이 화면에 보이도록 했다.

 
{isOpen && <Modal />}

이 방식으로 모달이 열리고 닫히는 모든 흐름이 Redux 상태를 기준으로 동작하게 만들었다.

6. 모달 UI 구성

모달이 열렸을 때는 전체 화면 위에 어두운 반투명 오버레이가 깔리도록 구현했다.

 
<div className="fixed inset-0 z-50 grid place-items-center bg-zinc-950/30 px-4 backdrop-blur-sm">

그리고 가운데에는 확인 메시지와 버튼을 배치했다.

<h2>정말 삭제하시겠습니까?</h2>

사용자는 여기서 아니요를 눌러 취소하거나, 를 눌러 장바구니를 완전히 비울 수 있다.

7. Reducer 중심 상태 관리

이 실습에서 가장 중요한 조건은 모달 상태를 useState로 관리하지 않는 것이었다.

모달은 간단한 UI라서 useState로도 충분히 만들 수 있다.
하지만 이번에는 Redux Toolkit을 연습하는 목적이 있었기 때문에, 모달의 열림/닫힘 상태도 Slice로 분리해서 관리했다.

최종 흐름은 다음과 같다.

 
전체 삭제 버튼 클릭
→ dispatch(openModal())
→ modal.isOpen이 true로 변경
→ Modal 컴포넌트 렌더링
→ 아니요 클릭 시 dispatch(closeModal())
→ 네 클릭 시 dispatch(clearCart()) + dispatch(closeModal())

이 흐름을 통해 UI 상태 역시 Redux Store에서 관리할 수 있다는 점을 이해할 수 있었다.

8.  배운 점

장바구니 데이터 상태뿐만 아니라 모달 UI 상태까지 Redux Toolkit으로 관리했다.

  • 장바구니 데이터는 cartSlice
  • 모달 열림/닫힘 상태는 modalSlice

이렇게 관심사를 분리하니 코드 구조가 더 명확해졌다.

또한 모달 내부에서 다른 Slice의 액션인 clearCart()를 호출하는 흐름도 경험할 수 있었다.
즉, 하나의 컴포넌트 안에서 여러 Slice의 액션을 조합해 실제 기능을 완성할 수 있었다.

 

Redux Toolkit은 단순히 서버 데이터나 리스트 상태만 관리하는 것이 아니다.

모달처럼 UI 상태를 관리하는 데에도 사용할 수 있다는 것을 알게 되었다.