Skip to content

Commit

Permalink
refactor: 자동완성창 외부 클릭시 창닫기 로직을 id 대신 ref 를 활용하여 수정(#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbgksqkr committed Jun 19, 2024
1 parent 6e0b709 commit 1575188
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import styled from 'styled-components';

export const ItemWrapper = styled.div`
padding: 15px;
export const OptionWrapper = styled.div`
padding: 16px;
font-size: 1.4rem;
cursor: pointer;
&:hover {
background-color: lightgrey;
}
`;

export const NoResultWrapper = styled.span`
padding: 15px;
padding: 16px;
font-size: 1.4rem;
box-shadow: 2px 2px 2px black;
`;

export const AutoCompleteWrapper = styled.div`
position: absolute;
display: flex;
flex-direction: column;
gap: 10px;
width: 320px;
margin: 0 0 0 20px;
background-color: white;
box-shadow: 2px 2px 2px black;
z-index: 1;
`;
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import { useSearchAutoCompleteQuery } from '@/hooks/useSearchAutoCompleteQuery';
import { useRouter } from 'next/navigation';
import * as S from './AutoCompleteContainer.styled';
import { RefObject } from 'react';

interface AutoCompleteContainerProps {
searchInput: string;
autoCompleteRef: RefObject<HTMLDivElement>;
}

const AutoCompleteContainer = ({ searchInput }: AutoCompleteContainerProps) => {
const AutoCompleteContainer = ({ searchInput, autoCompleteRef }: AutoCompleteContainerProps) => {
const router = useRouter();
const { data: dropdownTitleList } = useSearchAutoCompleteQuery(searchInput);

if (dropdownTitleList.length === 0) {
return <S.NoResultWrapper>검색 결과가 없습니다.</S.NoResultWrapper>;
}
const { data: autoCompleteList } = useSearchAutoCompleteQuery(searchInput);

return (
<>
{dropdownTitleList.map((title, idx) => (
<S.ItemWrapper id="complete" key={idx} onClick={() => router.push(`search/?search=${title}`)}>
{title}
</S.ItemWrapper>
))}
</>
<S.AutoCompleteWrapper ref={autoCompleteRef}>
{autoCompleteList.length > 0 ? (
autoCompleteList.map((title, idx) => (
<S.OptionWrapper key={idx} onClick={() => router.push(`search/?search=${title}`)}>
{title}
</S.OptionWrapper>
))
) : (
<S.NoResultWrapper>검색 결과가 없습니다.</S.NoResultWrapper>
)}
</S.AutoCompleteWrapper>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as S from './AutoCompleteContainer.styled';

const AutoCompleteLoading = () => {
return (
<S.AutoCompleteWrapper>
<S.NoResultWrapper>검색중...</S.NoResultWrapper>
</S.AutoCompleteWrapper>
);
};

export default AutoCompleteLoading;
26 changes: 9 additions & 17 deletions src/components/search/searchPageForm/SearchPageForm.styled.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
import styled from 'styled-components';

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

export const SearchBarInput = styled.input`
width: 32rem;
height: 2.5rem;
padding: 10px 10px 10px 30px;
border: none;
background: url('/img/search_bar.png');
background-repeat: no-repeat;
background-size: contain;
border: none;
font-size: 2rem;
font-family: Pretendard;
padding: 10px;
padding-left: 30px;
width: 55rem;
height: 2.5rem;
&:focus {
outline: none;
}
`;

export const BoxWrapper = styled.div`
display: flex;
flex-direction: column;
width: 40vw;
background-color: white;
margin-left: 2%;
gap: 10px;
box-shadow: 2px 2px 2px black;
z-index: 1;
`;

export const NoResultWrapper = styled.span`
padding: 15px;
font-size: 1.4rem;
Expand Down
40 changes: 23 additions & 17 deletions src/components/search/searchPageForm/SearchPageForm.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,51 @@
import { Suspense, useEffect } from 'react';
import { Suspense, useEffect, useRef } from 'react';
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';

const SearchPageForm = ({ searchKeyword }: { searchKeyword?: string }) => {
const { values, isFocused, handleFocus, handleBlur, handleChange, handleSearchSubmit } = useSearchForm({
initialValue: { searchInput: searchKeyword || '', searchHeaderInput: searchKeyword || '' },
});
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 body = document.querySelector('body')!;
body.addEventListener('click', (e: MouseEvent) => {
if (e.target instanceof HTMLDivElement && e.target.id !== 'complete') {
handleBlur();
}
});
return body.removeEventListener('click', (e) => {
if (e.target instanceof HTMLDivElement && e.target.id !== 'complete') {
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.SearchBarInput
id="complete"
name="searchInput"
placeholder="검색어를 입력하세요..."
value={values.searchInput}
onChange={handleChange}
onFocus={handleFocus}
autoComplete="off"
ref={inputRef}
/>
<S.BoxWrapper>
<Suspense fallback={<S.NoResultWrapper>검색중...</S.NoResultWrapper>}>
{isFocused && values.searchInput.length > 0 && <AutoCompleteContainer searchInput={debounceSearchInput} />}
</Suspense>
</S.BoxWrapper>
<Suspense fallback={<AutoCompleteLoading />}>
{isSearching && <AutoCompleteContainer searchInput={debounceSearchInput} autoCompleteRef={autoCompleteRef} />}
</Suspense>
</S.FormWrapper>
);
};
Expand Down

0 comments on commit 1575188

Please sign in to comment.