From 59ba431e340508556d3593b8c81871b83197c6e0 Mon Sep 17 00:00:00 2001 From: simhorim Date: Fri, 9 Aug 2024 17:33:48 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat(useLeadingDebounce):=20=EC=84=A0?= =?UTF-8?q?=ED=96=89=20=EB=94=94=EB=B0=94=EC=9A=B4=EB=93=9C=20=ED=9B=85=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/useLeadingDebounce.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 frontend/src/hooks/useLeadingDebounce.ts diff --git a/frontend/src/hooks/useLeadingDebounce.ts b/frontend/src/hooks/useLeadingDebounce.ts new file mode 100644 index 00000000..bbd29607 --- /dev/null +++ b/frontend/src/hooks/useLeadingDebounce.ts @@ -0,0 +1,19 @@ +import { useState } from "react"; + +const useLeadingDebounce = (callback: () => void, delay: number) => { + const [isDebouncing, setIsDebouncing] = useState(false); + + const debouncedCallback = () => { + if (!isDebouncing) { + callback(); + setIsDebouncing(true); + setTimeout(() => { + setIsDebouncing(false); + }, delay); + } + }; + + return debouncedCallback; +}; + +export default useLeadingDebounce; From 6e0b374c9638e014efed7668223c05b83727657e Mon Sep 17 00:00:00 2001 From: simhorim Date: Fri, 9 Aug 2024 17:34:16 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=EC=82=AD=EC=A0=9C=20=EB=B0=98?= =?UTF-8?q?=EB=B3=B5=20=EC=9A=94=EC=B2=AD=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/travelPlanDetail/TravelPlanDetailPage.tsx | 9 +++++---- .../pages/travelogueDetail/TravelogueDetailPage.tsx | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/pages/travelPlanDetail/TravelPlanDetailPage.tsx b/frontend/src/components/pages/travelPlanDetail/TravelPlanDetailPage.tsx index a5108ad2..66d18a36 100644 --- a/frontend/src/components/pages/travelPlanDetail/TravelPlanDetailPage.tsx +++ b/frontend/src/components/pages/travelPlanDetail/TravelPlanDetailPage.tsx @@ -15,6 +15,7 @@ import TravelPlanDetailSkeleton from "@components/pages/travelPlanDetail/TravelP import TravelPlansTabContent from "@components/pages/travelPlanDetail/TravelPlansTabContent/TravelPlansTabContent"; import useClickAway from "@hooks/useClickAway"; +import useLeadingDebounce from "@hooks/useLeadingDebounce"; import { ERROR_MESSAGE_MAP } from "@constants/errorMessage"; import { ROUTE_PATHS_MAP } from "@constants/route"; @@ -30,11 +31,9 @@ import * as S from "./TravelPlanDetailPage.styled"; const TravelPlanDetailPage = () => { const location = useLocation(); - - const { onTransformTravelDetail } = useTravelTransformDetailContext(); - const id = extractId(location.pathname); + const { onTransformTravelDetail } = useTravelTransformDetailContext(); const { data, status, error } = useGetTravelPlan(id); const navigate = useNavigate(); @@ -69,8 +68,10 @@ const TravelPlanDetailPage = () => { setIsDeleteModalOpen((prev) => !prev); }; + const debouncedClickDeleteButton = useLeadingDebounce(() => deleteTravelPlan(Number(id)), 3000); + const handleClickDeleteButton = () => { - deleteTravelPlan(Number(id)); + debouncedClickDeleteButton(); }; //TODO: 수정 이벤트 추가해야함 diff --git a/frontend/src/components/pages/travelogueDetail/TravelogueDetailPage.tsx b/frontend/src/components/pages/travelogueDetail/TravelogueDetailPage.tsx index 5c8aa55a..4d742eac 100644 --- a/frontend/src/components/pages/travelogueDetail/TravelogueDetailPage.tsx +++ b/frontend/src/components/pages/travelogueDetail/TravelogueDetailPage.tsx @@ -13,6 +13,7 @@ import TravelogueDetailSkeleton from "@components/pages/travelogueDetail/Travelo import TravelogueTabContent from "@components/pages/travelogueDetail/TravelogueTabContent/TravelogueTabContent"; import useClickAway from "@hooks/useClickAway"; +import useLeadingDebounce from "@hooks/useLeadingDebounce"; import useUser from "@hooks/useUser"; import { ROUTE_PATHS_MAP } from "@constants/route"; @@ -58,8 +59,10 @@ const TravelogueDetailPage = () => { setIsDeleteModalOpen((prev) => !prev); }; + const debouncedClickDeleteButton = useLeadingDebounce(() => deleteTravelogue(Number(id)), 3000); + const handleClickDeleteButton = () => { - deleteTravelogue(Number(id)); + debouncedClickDeleteButton(); }; //TODO: 수정 이벤트 추가해야함 From 091a9e286322237974817c707fb5c515c9d01bd3 Mon Sep 17 00:00:00 2001 From: simhorim Date: Fri, 9 Aug 2024 17:34:23 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=EB=93=B1=EB=A1=9D=20=EB=B0=98?= =?UTF-8?q?=EB=B3=B5=20=EC=9A=94=EC=B2=AD=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../travelPlanRegister/TravelPlanRegisterPage.tsx | 9 +++++++-- .../travelogueRegister/TravelogueRegisterPage.tsx | 13 ++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/pages/travelPlanRegister/TravelPlanRegisterPage.tsx b/frontend/src/components/pages/travelPlanRegister/TravelPlanRegisterPage.tsx index 57cfdc0e..2345d34d 100644 --- a/frontend/src/components/pages/travelPlanRegister/TravelPlanRegisterPage.tsx +++ b/frontend/src/components/pages/travelPlanRegister/TravelPlanRegisterPage.tsx @@ -19,6 +19,7 @@ import Calendar from "@components/common/Calendar/Calendar"; import TravelPlanDayAccordion from "@components/pages/travelPlanRegister/TravelPlanDayAccordion/TravelPlanDayAccordion"; import { useTravelPlanDays } from "@hooks/pages/useTravelPlanDays"; +import useLeadingDebounce from "@hooks/useLeadingDebounce"; import useUser from "@hooks/useUser"; import { ERROR_MESSAGE_MAP } from "@constants/errorMessage"; @@ -62,7 +63,7 @@ const TravelPlanRegisterPage = () => { const navigate = useNavigate(); - const handleConfirmBottomSheet = async () => { + const handleRegisterTravelPlan = () => { const formattedStartDate = startDate ? new Date(startDate.getTime() - startDate.getTimezoneOffset() * 60000) .toISOString() @@ -78,8 +79,12 @@ const TravelPlanRegisterPage = () => { }, }, ); + }; + + const debouncedRegisterTravelPlan = useLeadingDebounce(() => handleRegisterTravelPlan(), 3000); - handleCloseBottomSheet(); + const handleConfirmBottomSheet = () => { + debouncedRegisterTravelPlan(); }; const { mutate: handleAddTravelPlan } = usePostTravelPlan(); diff --git a/frontend/src/components/pages/travelogueRegister/TravelogueRegisterPage.tsx b/frontend/src/components/pages/travelogueRegister/TravelogueRegisterPage.tsx index f77d10e9..7714ac60 100644 --- a/frontend/src/components/pages/travelogueRegister/TravelogueRegisterPage.tsx +++ b/frontend/src/components/pages/travelogueRegister/TravelogueRegisterPage.tsx @@ -21,6 +21,7 @@ import { import TravelogueDayAccordion from "@components/pages/travelogueRegister/TravelogueDayAccordion/TravelogueDayAccordion"; import { useTravelogueDays } from "@hooks/pages/useTravelogueDays"; +import useLeadingDebounce from "@hooks/useLeadingDebounce"; import useUser from "@hooks/useUser"; import { ERROR_MESSAGE_MAP } from "@constants/errorMessage"; @@ -78,8 +79,8 @@ const TravelogueRegisterPage = () => { const navigate = useNavigate(); - const handleConfirmBottomSheet = () => { - handleRegisterTravelogue( + const handleRegisterTravelogue = () => { + registerTravelogueMutate( { title, thumbnail, days: travelogueDays }, { onSuccess: ({ data: { id } }) => { @@ -90,7 +91,13 @@ const TravelogueRegisterPage = () => { ); }; - const { mutate: handleRegisterTravelogue } = usePostTravelogue(); + const debouncedRegisterTravelogue = useLeadingDebounce(() => handleRegisterTravelogue(), 3000); + + const handleConfirmBottomSheet = () => { + debouncedRegisterTravelogue(); + }; + + const { mutate: registerTravelogueMutate } = usePostTravelogue(); const { user } = useUser(); From 691ab751170e048f0e3e842d7787fe0e924eb556 Mon Sep 17 00:00:00 2001 From: simhorim Date: Tue, 13 Aug 2024 18:11:26 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor(useLeadingDebounce):=20=EB=A0=8C?= =?UTF-8?q?=EB=8D=94=EB=A7=81=EA=B3=BC=20=EB=AC=B4=EA=B4=80=ED=95=98?= =?UTF-8?q?=EA=B8=B0=EC=97=90=20useState=20=EC=97=90=EC=84=9C=20useRef?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/useLeadingDebounce.ts | 27 ++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/frontend/src/hooks/useLeadingDebounce.ts b/frontend/src/hooks/useLeadingDebounce.ts index bbd29607..cfb7cc4f 100644 --- a/frontend/src/hooks/useLeadingDebounce.ts +++ b/frontend/src/hooks/useLeadingDebounce.ts @@ -1,18 +1,33 @@ -import { useState } from "react"; +import { useEffect, useRef } from "react"; const useLeadingDebounce = (callback: () => void, delay: number) => { - const [isDebouncing, setIsDebouncing] = useState(false); + const isDebouncing = useRef(false); + const timeoutRef = useRef>(); const debouncedCallback = () => { - if (!isDebouncing) { + const isDebounceReady = !isDebouncing.current; + const isExistingTimerActive = isDebounceReady && timeoutRef.current; + + if (isExistingTimerActive) clearTimeout(timeoutRef.current); + + if (isDebounceReady) { callback(); - setIsDebouncing(true); - setTimeout(() => { - setIsDebouncing(false); + isDebouncing.current = true; + + timeoutRef.current = setTimeout(() => { + isDebouncing.current = false; }, delay); } }; + useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }; + }, []); + return debouncedCallback; };