Skip to content

Commit

Permalink
refactor: 자동완성창 관리하는 로직을 useFocusSearchInput 커스텀 훅으로 분리하고 불필요한 form 형…
Browse files Browse the repository at this point in the history
…식 제거(#120)
  • Loading branch information
rbgksqkr committed Jun 19, 2024
1 parent 1575188 commit 83088d2
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 80 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from 'styled-components';

export const FormWrapper = styled.form`
export const SearchInputWrapper = styled.div`
position: relative;
`;

Expand Down
56 changes: 24 additions & 32 deletions src/components/search/searchPageForm/SearchPageForm.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement | null>(null);
const autoCompleteRef = useRef<HTMLDivElement | null>(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 (
<S.FormWrapper name="searchInput" onSubmit={handleSearchSubmit}>
<S.SearchInputWrapper>
<S.SearchBarInput
name="searchInput"
ref={inputRef}
value={searchInput}
placeholder="검색어를 입력하세요..."
value={values.searchInput}
onChange={handleChange}
onFocus={handleFocus}
onKeyDown={handleKeydown}
autoComplete="off"
ref={inputRef}
/>
<Suspense fallback={<AutoCompleteLoading />}>
{isSearching && <AutoCompleteContainer searchInput={debounceSearchInput} autoCompleteRef={autoCompleteRef} />}
</Suspense>
</S.FormWrapper>
</S.SearchInputWrapper>
);
};

Expand Down
33 changes: 33 additions & 0 deletions src/hooks/useFocusSearchInput.ts
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement | null>(null);
const autoCompleteRef = useRef<HTMLDivElement | null>(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;
31 changes: 31 additions & 0 deletions src/hooks/useInput.ts
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement>) => {
setValue(e.target.value);
};

const handleFocus = () => {
setIsFocused(true);
};

const handleBlur = useCallback(() => {
setIsFocused(false);
}, []);

const handleKeydown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.code === 'Enter') {
handleBlur();
router.push(`search/?search=${value}`);
}
};

return { value, isFocused, handleChange, handleFocus, handleBlur, handleKeydown };
};

export default useInput;
47 changes: 0 additions & 47 deletions src/hooks/useSearchForm.ts

This file was deleted.

0 comments on commit 83088d2

Please sign in to comment.