React - 알림 (Polling)

sarang_daddy·2023년 12월 16일
0

React

목록 보기
25/26

처리해야하는 작업이 남아 있다면 아이콘을 활성화하여 사용자가 알 수 있도록 인터페이스(알림)을 제공하는 기능을 구현해보자.

처리 작업이 남아있다면 true 반환 API

  • 해당 기능을 위해 서버에서 제공해주는 API는 클라이언트 요청시 반환을 해준다.
{
  "code": 200,
  "creator_application": true,
  "message": "SUCCESS"
}

1차 구현

  • 아이콘은 처리 작업이 필요한 사이드바 메뉴에 활성화 한다.
export default function AdminSidebarContainer() {
  const { data: session } = useSession();
  const { data: newRequest } = useSWR(session ? `/main/side` : null, () =>
    session ? checkSidebar(session.user.token) : null
  );

  return (
    <div className="flex flex-col">
      <AdminSidebar menus={SIDEBAR_LIST} newRequest={newRequest} />
    </div>
  );
}
// AdminSidebar

// ...
// 새로운 요청 사항 있으면 아이콘 활성화
{newData?.creator_application &&
  subitem.href === "/admin/account/creator" && (
    <span
      className={` text-red-500 ${
        isSubmenuItemActive(subitem)
          ? "text-white "
          : ""
      },`}
    >
      <WarningIcon />
    </span>
  )}

  • 아이콘 활성화는 구현되었지만 아래와 같은 문제점이 남아있다.

추가 고려사항

  • 처리해야하는 작업은 실시간으로 업데이트 된다.
  • 언제 API를 요청해서 새로운 작업이 있는지 확인해야 할까?
  • 기획상 실시간 알림까지의 필요성을 없다.
  • 최대한 서버의 부담이 적은 방향으로 30분 간격의 확인으로 협의.
  • 처리 작업이 완료되면 즉시 아이콘이 사라져야 한다.
  • 작업 처리는 다른 컴포넌트에 존재한다.

커스텀훅으로 구현하여 여러 컴포넌트에서 동일한 요청이 가능하도록 구현

커스텀훅 생성

// hooks/useAdminSidebar.js
import useSWR from "swr";
import { checkSidebar } from "../services/adminSidebar.service";
import { useSession } from "next-auth/react";

export function useAdminSidebar() {
  const { data: session } = useSession();
  const { data, mutate } = useSWR(
    session ? `/admin/side` : null, // key
    () => (session ? checkSidebar(session.user.token) : null), // fetcher

    { refreshInterval: 1800000 } // 30분 간격으로 리플레쉬
  );

  return { data, refresh: mutate };
}
  • 처리 작업 존재 여부 값을 반환한다.
  • useSWRrefreshInterval 옵션으로 30분 간격으로 데이터를 새로고침한다.
  • 수동적으로 새로고침을 실행하기 위해 mutate(refresh)를 반환한다.

2차 구현

  • 사이드바는 커스텀훅을 통해 남은 작업 여부를 확인하고 30분마다 재확인한다.
import { AdminSidebar } from "@/admin/components/sidebar/AdminSidebar";
import { SIDEBAR_LIST } from "@/admin/constants/sidebarList";
import { useAdminSidebar } from "@/admin/hooks/useAdminSidebar";

export default function AdminSidebarContainer() {
  const { data: newData } = useAdminSidebar();

  return (
    <div className="flex flex-col">
      <AdminSidebar menus={SIDEBAR_LIST} newData={newData} />
    </div>
  );
}
  • 작업 처리가 완료되면 refrash를 통해 데이터를 즉시 업데이트한다.
export default function EditCreatorContainer({
  applyId,
  offStateSettingModal,
}: EditCreatorContainerProps) {

  // useAdminSidebar 커스텀훅의 refresh 가져오기
  const { refresh } = useAdminSidebar();

  // 이벤트 핸들러
  const handleUpdate = async (data: FormData) => {
    if (!session) return;

    try {
      const response = await updateCreator(session.user.token, data);
      if (response) {
        mutate();
        offStateSettingModal();

        toast({
          title: "크리에이터 승인 요청이 처리 되었습니다.",
          className: "bg-white",
        });
      }
    } catch (error) {
      if (error instanceof Error && "response" in error) {
        const responseError = error as any;

        let errorMessage = "크리에이터 승인 요청 처리에 실패했습니다.";
        if (
          responseError.response &&
          responseError.response.data &&
          responseError.response.data.message
        ) {
          errorMessage = responseError.response.data.message;
        }

        toast({
          title: errorMessage,
          className: "bg-red-500 text-white",
        });
      } else {
        toast({
          title: "알 수 없는 오류가 발생했습니다.",
          className: "bg-red-500 text-white",
        });
      }
    }
    refresh(); // 작업이 처리되면 남은 작업 여부 데이터를 새로고침 해준다.
  };

profile
한 발자국, 한 걸음 느리더라도 하루하루 발전하는 삶을 살자.

0개의 댓글