Skip to content

[9주차/조이] 워크북 제출합니다.#91

Open
aeongiing wants to merge 5 commits into
UMC-Inha:조이/mainfrom
aeongiing:main
Open

[9주차/조이] 워크북 제출합니다.#91
aeongiing wants to merge 5 commits into
UMC-Inha:조이/mainfrom
aeongiing:main

Conversation

@aeongiing
Copy link
Copy Markdown
Member

@aeongiing aeongiing commented May 27, 2026

✅ 워크북 체크리스트

  • 모든 핵심 키워드 정리를 마쳤나요?
  • 핵심 키워드에 대해 완벽히 이해하셨나요?
  • 이론 학습 이후 직접 실습을 해보는 시간을 가졌나요?
  • 미션을 수행하셨나요?
  • 미션을 기록하셨나요?

✅ 컨벤션 체크리스트

  • 디렉토리 구조 컨벤션을 잘 지켰나요?
  • pr 제목을 컨벤션에 맞게 작성하였나요?
  • pr에 해당되는 이슈를 연결하였나요?(중요)
  • 적절한 라벨을 설정하였나요?
  • 파트장에게 code review를 요청하기 위해 reviewer를 등록하였나요?
  • 닉네임/main 브랜치의 최신 상태를 반영하고 있는지 확인했나요?(매우 중요!)

📌 주안점

@aeongiing aeongiing self-assigned this May 27, 2026
@aeongiing aeongiing requested a review from qkrdmsthff as a code owner May 27, 2026 15:08
@aeongiing aeongiing changed the title keyword: 9주차 키워드 인증 [9주차/조이] 워크북 제출합니다. May 27, 2026
@aeongiing aeongiing linked an issue May 27, 2026 that may be closed by this pull request
Comment on lines +53 to +55
i.id === id ? { ...i, amount: i.amount - 1 } : i,
);
return { cartItems: items, ...calcTotals(items) };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zustand 스토어 내부에서 액션이 발생할 때마다 전개 연산자를 활용해 amount와 total을 동기화 한 덕분에 외부 호출 누락으로 인한 동기화 버그는 잘 방어된 것 같습니다.

다만, 현재 구조를 보면 두 가지 아쉬운 점이 보입니다.
increase, decrease 등에서 이미 ...calcTotals로 상태를 갱신하고 있기 때문에, 하단의 calculateTotals 액션은 사실상 아무 일도 하지 않는 코드가 되어버립니다.

cartItems만 알면 언제든 유도할 수 있는 amount와 total을 스토어의 상태로 중복 저장하다 보니, 모든 액션마다 ...calcTotals(items)를 의무적으로 결합해야 하는 번거로움이 있습니다.

Zustand의 셀렉터기능을 활용해 계산 로직을 외부 커스텀 훅으로 분리하면, 중복 상태와 죽은 액션을 걷어낼 수 있습니다.

초안 코드를 첨부하겠습니다

interface CartStore {
  cartItems: CartItem[];
  isOpen: boolean;
  increase: (id: string) => void;
  decrease: (id: string) => void;
  removeItem: (id: string) => void;
  clearCart: () => void;
  openModal: () => void;
  closeModal: () => void;
}

//  스토어는 cartItems, isOpen와 액션만 관리합니다.
export const useCartStore = create<CartStore>((set) => ({
  cartItems: mockCartItems,
  isOpen: false,

  increase: (id) =>
    set((state) => ({
      cartItems: state.cartItems.map((i) =>
        i.id === id ? { ...i, amount: i.amount + 1 } : i
      ),
    })),

  decrease: (id) =>
    set((state) => {
      const item = state.cartItems.find((i) => i.id === id);
      if (!item) return {};
      return {
        cartItems:
          item.amount <= 1
            ? state.cartItems.filter((i) => i.id !== id)
            : state.cartItems.map((i) => (i.id === id ? { ...i, amount: i.amount - 1 } : i)),
      };
    }),

  removeItem: (id) =>
    set((state) => ({
      cartItems: state.cartItems.filter((i) => i.id !== id),
    })),

  clearCart: () => set({ cartItems: [], isOpen: false }),
  openModal: () => set({ isOpen: true }),
  closeModal: () => set({ isOpen: false }),
}));

//  계산용 Selector 훅 분리
export const useCartTotals = () => {
  const cartItems = useCartStore((state) => state.cartItems);

  const amount = cartItems.reduce((sum, item) => sum + item.amount, 0);
  const total = cartItems.reduce((sum, item) => sum + Number(item.price) * item.amount, 0);

  return { amount, total };
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chapter09_Redux Toolkit & Zustand

2 participants