Next.js

캐시 활용으로 누락된 서버데이터 처리

해보구 2025. 3. 1. 22:01
반응형
POS 시스템에서 메뉴 데이터를 효율적으로 다루기 위해 usePosStore.ts라는 파일을 수정했다. 여기서 중요한 작업은 메뉴의 고유 번호(menuId)를 항상 확보하는 것이었다. 서버에서 데이터를 받아올 때 menuId가 빠져 있으면 문제가 생기는데, 이를 해결하기 위해 캐시라는 저장소를 활용했다.
 

문제: menuId가 빠진 데이터


POS 시스템은 주문을 표시할 때 각 메뉴의 고유 번호(menuId)가 필요하다. 예를 들어, "라떼"라는 메뉴를 삭제하려면 그 메뉴의 menuId를 알아야 한다. 근데 서버에서 데이터를 받아올 때 가끔 이런 식으로 menuId 없이 오는 경우가 있었다:

 

{
  "menuName": "matcha",
  "totalPrice": 4500,
  "totalCount": 1
}

 

로그에서 확인한 결과:
[fetchUnpaidOrderByPlace] Menu ID not found for matcha in menuCache

 

 

menuId가 없으면 삭제나 주문 처리가 안 돼서 골치 아팠다.


해결책: 캐시라는 저장소 활용


캐시는 이미 가져온 데이터를 저장해두는 곳이다. 생각한 방법은 간단했다: 모든 메뉴의 정보를 미리 캐시에 저장하고, 서버에서 menuId가 빠진 데이터를 주면 캐시에서 찾아 채우자.


1. 캐시에 메뉴 정보 저장하기
fetchMenusByCategory라는 함수는 서버에서 메뉴 목록을 가져와 캐시에 저장한다. 예를 들어, 카테고리 ID가 21인 메뉴를 요청하면:

 
 
fetchMenusByCategory: async (categoryId: number) => {
  set({ isLoading: true });
  const { menuCache } = get();
  if (menuCache[categoryId]) {
    set({ currentMenus: menuCache[categoryId], isLoading: false });
    return;
  }
  try {
    const { data } = await axiosInstance.get(`/api/menus/all/${categoryId}`);
    const transformed = data.map((menu: any) => ({
      ...menu,
      menuId: menu.menuId ?? null,
    }));
    set((state) => ({
      menuCache: { ...state.menuCache, [categoryId]: transformed },
      currentMenus: transformed,
      isLoading: false,
    }));
  } catch (err) {
    console.error("fetchMenusByCategory error:", err);
    set({ currentMenus: [], isLoading: false });
  }
},

 

 

서버 응답:
[
  { "menuId": 35, "menuName": "americano", "price": 5000 },
  { "menuId": 36, "menuName": "latte", "price": 3500 },
  { "menuId": 37, "menuName": "matcha", "price": 4500 }
]

 

  • 이 데이터를 menuCache[21]에 저장해서 나중에 쓸 수 있게 했다.
 

 

 

 

2. menuId 없는 데이터 채우기
fetchUnpaidOrderByPlace는 주문 데이터를 가져오는 함수다. 여기서 menuId가 없으면 캐시에서 찾아 넣었다:

 

 

fetchUnpaidOrderByPlace: async (placeId: number) => {
  set({ isLoading: true });
  try {
    const { data } = await axiosInstance.get(`/api/orders/places/${placeId}`);
    if (data && data.orderStatus === "UNPAID") {
      const selectedItems = data.menuDetail.map((menu: any) => {
        let menuId = menu.menuId ?? null;
        if (!menuId) {
          const allMenus = Object.values(get().menuCache).flat();
          const found = allMenus.find((m) => m.menuName === menu.menuName);
          if (found) menuId = found.menuId;
        }
        return {
          menuName: menu.menuName,
          price: menu.totalPrice / menu.totalCount,
          quantity: menu.totalCount,
          menuId,
        };
      });
      set({
        orderId: data.orderId,
        selectedItems,
        placeId,
        tableName: data.placeName,
        storeId: data.storeId,
        isLoading: false,
      });
    } else {
      set({ orderId: null, selectedItems: [], placeId, isLoading: false });
    }
  } catch (err) {
    console.error("fetchUnpaidOrderByPlace error:", err);
    set({ orderId: null, selectedItems: [], placeId, isLoading: false });
  }
},

 

 

 

로그 확인:
[fetchUnpaidOrderByPlace] Found menuId 37 for matcha in menuCache
선택된 메뉴: [{menuName: 'matcha', price: 4500, quantity: 1, menuId: 37}]

 

캐시 덕분에 menuId가 37로 채워졌다.

 

 

작동 단계 ::

  • 첫 단계: fetchMenusByCategory로 메뉴 목록을 가져와 menuCache에 저장.
  • 두 번째 단계: fetchUnpaidOrderByPlace에서 주문 데이터를 받아오고, menuId가 없으면 menuCache에서 menuName으로 검색해 채움.
  • 결과: 모든 메뉴에 menuId가 포함되어 삭제와 주문 처리가 문제없이 됐다.

장점

  • 서버가 menuId를 안 줘도 캐시로 보완 가능.
  • 요청 횟수 줄여서 속도 빨라짐.

 

회고


menuId를 캐시로 보완하는 건 처음엔 복잡해 보였지만, 단계별로 풀어보니 이해가 됐다. 서버 데이터가 불완전할 때 캐시를 쓰는 방법이 유용했다. 코드가 약간 길어졌지만 필요한 로직이라 괜찮았다. 다음엔 서버에서 데이터를 제대로 주는지 먼저 확인해야겠다. 캐시 활용으로 문제를 해결한 게 유익했다.

반응형