From 83088d28c0047bc3dda47be3a24954ba4f33387a Mon Sep 17 00:00:00 2001 From: rbgksqkr Date: Wed, 19 Jun 2024 15:21:52 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=9E=90=EB=8F=99=EC=99=84?= =?UTF-8?q?=EC=84=B1=EC=B0=BD=20=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20useFocusSearchInput=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EA=B3=A0=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20form=20=ED=98=95=EC=8B=9D=20=EC=A0=9C=EA=B1=B0(#120?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../searchPageForm/SearchPageForm.styled.ts | 2 +- .../search/searchPageForm/SearchPageForm.tsx | 56 ++++++++----------- src/hooks/useFocusSearchInput.ts | 33 +++++++++++ src/hooks/useInput.ts | 31 ++++++++++ src/hooks/useSearchForm.ts | 47 ---------------- 5 files changed, 89 insertions(+), 80 deletions(-) create mode 100644 src/hooks/useFocusSearchInput.ts create mode 100644 src/hooks/useInput.ts delete mode 100644 src/hooks/useSearchForm.ts diff --git a/src/components/search/searchPageForm/SearchPageForm.styled.ts b/src/components/search/searchPageForm/SearchPageForm.styled.ts index 43f052b..7f88976 100644 --- a/src/components/search/searchPageForm/SearchPageForm.styled.ts +++ b/src/components/search/searchPageForm/SearchPageForm.styled.ts @@ -1,6 +1,6 @@ import styled from 'styled-components'; -export const FormWrapper = styled.form` +export const SearchInputWrapper = styled.div` position: relative; `; diff --git a/src/components/search/searchPageForm/SearchPageForm.tsx b/src/components/search/searchPageForm/SearchPageForm.tsx index e711057..1ac05d8 100644 --- a/src/components/search/searchPageForm/SearchPageForm.tsx +++ b/src/components/search/searchPageForm/SearchPageForm.tsx @@ -1,52 +1,44 @@ -import { Suspense, useEffect, useRef } from 'react'; +import { Suspense } from 'react'; +import * as S from './SearchPageForm.styled'; import useDebounceValue from '@/hooks/useDebounce'; -import useSearchForm from '@/hooks/useSearchForm'; import AutoCompleteContainer from '../autoCompleteContainer/AutoCompleteContainer'; -import * as S from './SearchPageForm.styled'; import AutoCompleteLoading from '../autoCompleteContainer/AutoCompleteLoading'; +import useFocusSearchInput from '@/hooks/useFocusSearchInput'; +import useInput from '@/hooks/useInput'; const SearchPageForm = ({ searchKeyword }: { searchKeyword?: string }) => { - const { values, isFocused, handleFocus, handleBlur, handleChange, handleSearchSubmit } = useSearchForm({ - initialValue: { searchInput: searchKeyword || '', searchHeaderInput: searchKeyword || '' }, + const { + value: searchInput, + isFocused, + handleChange, + handleFocus, + handleBlur, + handleKeydown, + } = useInput(searchKeyword || ''); + + const debounceSearchInput = useDebounceValue(searchInput, 300); + + const { inputRef, autoCompleteRef, isSearching } = useFocusSearchInput({ + isFocused, + searchInput, + handleBlur, }); - const debounceSearchInput = useDebounceValue(values.searchInput, 300); - - const inputRef = useRef(null); - const autoCompleteRef = useRef(null); - - const isSearching = isFocused && values.searchInput.length > 0; - - useEffect(() => { - const handleOutsideClose = (e: MouseEvent) => { - const isOutsideDropdown = - isFocused && - !autoCompleteRef.current?.contains(e.target as Node) && - !inputRef.current?.contains(e.target as Node); - - if (isOutsideDropdown) { - handleBlur(); - } - }; - document.addEventListener('click', handleOutsideClose); - - return () => document.removeEventListener('click', handleOutsideClose); - }, [isFocused]); return ( - + }> {isSearching && } - + ); }; diff --git a/src/hooks/useFocusSearchInput.ts b/src/hooks/useFocusSearchInput.ts new file mode 100644 index 0000000..ba88615 --- /dev/null +++ b/src/hooks/useFocusSearchInput.ts @@ -0,0 +1,33 @@ +import { useEffect, useRef } from 'react'; + +interface UseFocusSearchInputProps { + isFocused: boolean; + searchInput: string; + handleBlur: () => void; +} + +const useFocusSearchInput = ({ isFocused, searchInput, handleBlur }: UseFocusSearchInputProps) => { + const inputRef = useRef(null); + const autoCompleteRef = useRef(null); + const isSearching = isFocused && searchInput.length > 0; + + useEffect(() => { + const handleOutsideClose = (e: MouseEvent) => { + const isOutsideArea = + isFocused && + !autoCompleteRef.current?.contains(e.target as Node) && + !inputRef.current?.contains(e.target as Node); + + if (isOutsideArea) { + handleBlur(); + } + }; + document.addEventListener('click', handleOutsideClose); + + return () => document.removeEventListener('click', handleOutsideClose); + }, [isFocused, handleBlur]); + + return { inputRef, autoCompleteRef, isSearching }; +}; + +export default useFocusSearchInput; diff --git a/src/hooks/useInput.ts b/src/hooks/useInput.ts new file mode 100644 index 0000000..50f7d1d --- /dev/null +++ b/src/hooks/useInput.ts @@ -0,0 +1,31 @@ +import { useRouter } from 'next/navigation'; +import { ChangeEvent, useCallback, useState } from 'react'; + +const useInput = (initialValue: string) => { + const router = useRouter(); + const [value, setValue] = useState(initialValue); + const [isFocused, setIsFocused] = useState(false); + + const handleChange = (e: ChangeEvent) => { + setValue(e.target.value); + }; + + const handleFocus = () => { + setIsFocused(true); + }; + + const handleBlur = useCallback(() => { + setIsFocused(false); + }, []); + + const handleKeydown = (e: React.KeyboardEvent) => { + if (e.code === 'Enter') { + handleBlur(); + router.push(`search/?search=${value}`); + } + }; + + return { value, isFocused, handleChange, handleFocus, handleBlur, handleKeydown }; +}; + +export default useInput; diff --git a/src/hooks/useSearchForm.ts b/src/hooks/useSearchForm.ts deleted file mode 100644 index 4103966..0000000 --- a/src/hooks/useSearchForm.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; - -type SearchInputType = 'searchInput' | 'searchHeaderInput'; - -interface useFormProps { - initialValue: Record; -} - -const useSearchForm = ({ initialValue }: useFormProps) => { - const router = useRouter(); - const [values, setValues] = useState(initialValue); - - const [isFocused, setIsFocused] = useState(false); - - const handleFocus = () => { - setIsFocused(true); - }; - - const handleBlur = () => { - setIsFocused(false); - }; - - const handleChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setValues({ ...values, [name]: value }); - }; - - const handleSearchSubmit = (e: React.ChangeEvent) => { - e.preventDefault(); - setIsFocused(false); - const { name } = e.target; - - if (name === 'searchInput' || name === 'searchHeaderInput') { - if (values[name].length === 0) { - alert('검색어를 입력해주세요'); - return; - } - setValues({ ...values, searchInput: values[name], searchHeaderInput: '' }); - router.push(`search/?search=${values[name]}`); - } - }; - - return { values, isFocused, handleChange, handleSearchSubmit, handleFocus, handleBlur }; -}; - -export default useSearchForm;