From 2bbeb676f2f6315fdbcfa8e7627ebec353eea922 Mon Sep 17 00:00:00 2001 From: feb-dain Date: Thu, 16 Nov 2023 14:35:24 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=9A=94=EC=B2=AD=20=EB=B3=B4=EB=82=B4=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#927] --- .../StationSearchWindow/StationSearchBar.tsx | 10 +-- .../hooks/useStationSearchWindow.tsx | 82 +++++++++++++------ .../hooks/tanstack-query/useSearchStations.ts | 2 +- frontend/src/hooks/useDebounce.ts | 13 ++- 4 files changed, 69 insertions(+), 38 deletions(-) diff --git a/frontend/src/components/ui/StationSearchWindow/StationSearchBar.tsx b/frontend/src/components/ui/StationSearchWindow/StationSearchBar.tsx index 2c52dfcd3..168e56a02 100644 --- a/frontend/src/components/ui/StationSearchWindow/StationSearchBar.tsx +++ b/frontend/src/components/ui/StationSearchWindow/StationSearchBar.tsx @@ -1,7 +1,5 @@ import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; -import { useSearchStations } from '@hooks/tanstack-query/useSearchStations'; - import FlexBox from '@common/FlexBox'; import Loader from '@common/Loader'; @@ -17,15 +15,11 @@ const StationSearchBar = () => { handleCloseResult, showStationDetails, isFocused, - debouncedSearchWord, - } = useStationSearchWindow(); - - const { - data: searchResult, + searchResult, isLoading, isError, isFetching, - } = useSearchStations(debouncedSearchWord); + } = useStationSearchWindow(); return ( diff --git a/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx b/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx index 19a889663..79409ad97 100644 --- a/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx +++ b/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx @@ -11,7 +11,8 @@ import { googleMapActions } from '@stores/google-maps/googleMapStore'; import { markerInstanceStore } from '@stores/google-maps/markerInstanceStore'; import { useStationInfoWindow } from '@hooks/google-maps/useStationInfoWindow'; -import { fetchSearchedStations } from '@hooks/tanstack-query/useSearchStations'; +import type { SearchedStationResponse } from '@hooks/tanstack-query/useSearchStations'; +import { fetchSearchedStations, useSearchStations } from '@hooks/tanstack-query/useSearchStations'; import { useDebounce } from '@hooks/useDebounce'; import useMediaQueries from '@hooks/useMediaQueries'; @@ -33,6 +34,8 @@ export const useStationSearchWindow = () => { const [searchWord, setSearchWord] = useState(''); const [debouncedSearchWord, setDebouncedSearchWord] = useState(searchWord); + const [userSearchWord, setUserSearchWord] = useState(''); + const [isSubmitted, setIsSubmitted] = useState(false); const { openLastPanel } = useNavigationBar(); const { openStationInfoWindow } = useStationInfoWindow(); @@ -43,9 +46,17 @@ export const useStationSearchWindow = () => { setDebouncedSearchWord(searchWord); }, [searchWord], - 400 + 400, + isSubmitted ); + const { + data: searchResult, + isLoading, + isError, + isFetching, + } = useSearchStations(debouncedSearchWord); + const handleOpenResult = ( event?: MouseEvent | FocusEvent ) => { @@ -60,31 +71,6 @@ export const useStationSearchWindow = () => { setIsFocused(false); }; - const handleSubmitSearchWord = async (event: FormEvent) => { - event.preventDefault(); - - const searchWordFromForm = new FormData(event.currentTarget).get('station-search'); - - if (encodeURIComponent(String(searchWordFromForm)) === searchWord) { - handleOpenResult(); - - return; - } - - handleCloseResult(); - - const searchedStations = await fetchSearchedStations(searchWord); - const isSearchedStationExisting = - searchedStations !== undefined && searchedStations.stations.length > 0; - - if (isSearchedStationExisting) { - const [{ stationId, latitude, longitude }] = searchedStations.stations; - showStationDetails({ stationId, latitude, longitude }); - } - - queryClient.invalidateQueries({ queryKey: [QUERY_KEY_SEARCHED_STATION] }); - }; - const showStationDetails = async ({ stationId, latitude, longitude }: StationPosition) => { googleMapActions.moveTo({ lat: latitude, lng: longitude }); @@ -122,9 +108,47 @@ export const useStationSearchWindow = () => { } }; + const showStationDetailsIfFound = (searchedStations: SearchedStationResponse) => { + const isSearchedStationExisting = searchedStations?.stations.length > 0; + + if (isSearchedStationExisting) { + const [{ stationId, latitude, longitude }] = searchedStations.stations; + showStationDetails({ stationId, latitude, longitude }); + handleCloseResult(); + + queryClient.invalidateQueries({ queryKey: [QUERY_KEY_SEARCHED_STATION] }); + } + }; + + const handleSubmitSearchWord = async (event: FormEvent) => { + event.preventDefault(); + handleCloseResult(); + setIsSubmitted(true); + + const searchWordFromForm = new FormData(event.currentTarget).get('station-search'); + const encodedSearchWord = encodeURIComponent(String(searchWordFromForm)); + const isSameAsPreviousSearchWord = encodedSearchWord === userSearchWord; + + if (isSameAsPreviousSearchWord) { + return; + } + + setUserSearchWord(encodedSearchWord); + + if (searchWord === debouncedSearchWord) { + showStationDetailsIfFound(searchResult); + + return; + } + + const searchedStations = await fetchSearchedStations(encodedSearchWord); + showStationDetailsIfFound(searchedStations); + }; + const handleChangeSearchWord = ({ target: { value } }: ChangeEvent) => { const searchWord = encodeURIComponent(value); + setIsSubmitted(false); handleOpenResult(); setSearchWord(searchWord); }; @@ -137,5 +161,9 @@ export const useStationSearchWindow = () => { showStationDetails, isFocused, debouncedSearchWord, + searchResult, + isLoading, + isError, + isFetching, }; }; diff --git a/frontend/src/hooks/tanstack-query/useSearchStations.ts b/frontend/src/hooks/tanstack-query/useSearchStations.ts index 51ec9129f..371c1ab79 100644 --- a/frontend/src/hooks/tanstack-query/useSearchStations.ts +++ b/frontend/src/hooks/tanstack-query/useSearchStations.ts @@ -7,7 +7,7 @@ import { SEARCH_SCOPE } from '@constants/stationSearch'; import type { SearchedCity, SearchedStation } from '@type/stations'; -interface SearchedStationResponse { +export interface SearchedStationResponse { stations: SearchedStation[]; cities: SearchedCity[]; } diff --git a/frontend/src/hooks/useDebounce.ts b/frontend/src/hooks/useDebounce.ts index 990de3738..44cdaa57d 100644 --- a/frontend/src/hooks/useDebounce.ts +++ b/frontend/src/hooks/useDebounce.ts @@ -1,11 +1,20 @@ import { useEffect, useCallback } from 'react'; -export const useDebounce = (func: (param: T) => void, dependencies: string[], delay: number) => { +export const useDebounce = ( + func: (param: T) => void, + dependencies: string[], + delay: number, + shouldClear?: boolean +) => { const callback = useCallback(func, dependencies); useEffect(() => { const timeout = setTimeout(callback, delay); + if (shouldClear) { + clearTimeout(timeout); + } + return () => clearTimeout(timeout); - }, [callback, delay]); + }, [callback, delay, shouldClear]); };