๐ ์ถ์ฒ ๊ฒ์์ด ๊ธฐ๋ฅ
๐ซ ๋ฐฑ์๋
- backend - prisma
// /api/keyword/[keyword].ts
// async ํจ์ ๋ด๋ถ์ ์๋ค๊ณ ๊ฐ์
const keywords = await prisma.keyword.findMany({
where: {
keyword: {
contains: keyword,
},
},
select: {
keyword: true,
},
});
๐ฌ ํ๋ก ํธ
1. ๋๋ฐ์ด์ค ์ ์ฉ
๋๋ฐ์ด์ค๋ ์ฐ์ํด์ ๊ฐ์ ์์ฒญ์ด ๋ค์ด์ฌ ๊ฒฝ์ฐ ์ ์ผ ๋ง์ง๋ง ์์ฒญ๋ง ์ ํจํ๊ฒ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ
์ํ ๊ฒ์์ ๊ฒฝ์ฐ ๊ฒ์์ด๋ฅผ ์ ๋ ฅํ ๋์ ์ด๋ฒคํธ์ ์ถ์ฒ ๊ฒ์์ด๋ฅผ ๋ฐ์์์ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ์ด ์๋๋ฐ ์ด๊ฒ์ ๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ์ง ์๊ฒ๋๋ฉด ์ฌ์ฉ์๊ฐ ํ๊ธ์๋ฅผ ๋๋ฅผ ๋๋ง๋ค ํ๋ฒ์ ์์ฒญ์ด ๋ ์๊ฐ๊ธฐ ๋๋ฌธ์ ์๋ฒ์ ๋ถ๋ด์ด ์ฌํด์ง ์ ์์ต๋๋ค.
์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํด์ ๊ฒ์์ด๋ฅผ ์ฐ์์ ์ผ๋ก ์ ๋ ฅํ ๋๋ ์๋ฒ๋ก ์์ฒญ์ ๋ณด๋ด์ง ์๋๋ก ์ฒ๋ฆฌํ์ต๋๋ค.
2. ํฌ์ปค์ฑ
์ถ์ฒ ๊ฒ์์ด๋ฅผ ๋ฐ์์ค๊ณ ๋์ ๋๋๋งํ์ ๊ฒฝ์ฐ ์ฌ์ฉ์๊ฐ ๊ฒ์์ฐฝ์ ํฌ์ปค์ค๋ฅผ ์คฌ์ ๊ฒฝ์ฐ์๋ง ์ถ์ฒ ๊ฒ์์ด๋ฅผ ๋ณด์ฌ์ฃผ๋๋ก ๋ง๋ค์์ต๋๋ค.
์ด๊ธฐ์๋ onFocus
์ onBlur
๋ฅผ ์ด์ฉํด์ ํฌ์ปค์ค๊ฐ ๋ ๋๋ฉด ์ถ์ฒ ๊ฒ์์ด๋ค์ด ์ฌ๋ผ์ง๋๋ก ๋ง๋ค์๋๋ฐ ๊ทธ๋ ๊ฒ ๊ตฌํํ๋ฉด ์ถ์ฒ ๊ฒ์์ด๋ฅผ ํด๋ฆญํ๊ฑฐ๋ ์ถ์ฒ ๊ฒ์์ด์ ํฌ์ปค์ค๋ฅผ ์ฃผ๋๋ก ์ด๋ํ ๊ฒฝ์ฐ์ ๊ฒ์์ฐฝ์ onBlur
๊ฐ ์คํ๋์ด ์ถ์ฒ ๊ฒ์์ด๋ค์ด ์ฌ๋ผ์ง๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์ด์ ์ ์ฌ์ฉํด๋ดค๋ ๋ชจ๋ฌ ์์ญ์ธ ํด๋ฆญ ์ ๋ซ๋ ๊ธฐ๋ฅ์ ๊ฐ์ ธ์์ ์ ์ฉํ์ต๋๋ค.
// 2022/04/16 - ํค์๋ ๊ฐ - by 1-blue ( react-hook-form์ useForm() )
const keyword = watch("keyword");
// 2022/04/16 - ํค์๋ ํฌ์ปค์ค ์ฌ๋ถ ๋ฐ ๊ด๋ จ ํค์๋ ๋ณด์ฌ์ค์ง ๊ฒฐ์ ํ ๋ณ์ - by 1-blue
const [isFocus, setIsFocus] = useState(false);
// 2022/04/16 - ํค์๋ ๊ฒ์ ์ ๋๋ฐ์ด์ค ์ ์ฉํ ๋ ์ฌ์ฉํ๋ ๋ณ์ - by 1-blue
const [debounce, setDebounce] = useState(false);
// 2022/04/16 - ํค์๋ ๊ฒ์ ์ ๋๋ฐ์ด์ค ์ ์ฉํ ๋ ์ฌ์ฉํ๋ ํจ์ - by 1-blue
const debounceKeyword = useCallback(() => setDebounce(true), [setDebounce]);
// 2022/04/16 - ํค์๋ ๊ฒ์ ์ ๋๋ฐ์ด์ค ์ ์ฉ - by 1-blue
useEffect(() => {
const timerId = setTimeout(debounceKeyword, 300);
return () => {
clearTimeout(timerId);
setDebounce(false);
};
}, [debounceKeyword, keyword, setDebounce]);
// ๊ฒ์์ฐฝ๊ณผ ์ถ์ฒ ๊ฒ์์ด๋ฅผ ์์์ผ๋ก ๊ฐ์ง๋ element
const wrapperRef = useRef<HTMLDivElement>(null);
// 2022/04/16 - ์์ญ์ธ ํด๋ฆญ ์ ์ถ์ฒ ํค์๋ ์ฐฝ ๋ซ๊ธฐ - by 1-blue
const handleCloseModal = useCallback(
(e: any) => {
if (
isFocus &&
(!wrapperRef.current || !wrapperRef.current.contains(e.target))
)
setIsFocus(false);
},
[isFocus, setIsFocus, wrapperRef]
);
// 2022/04/16 - ์ถ์ฒ ํค์๋ ์ฐฝ ๋ซ๊ธฐ ์ด๋ฒคํธ ๋ฑ๋ก - by 1-blue
useEffect(() => {
setTimeout(() => window.addEventListener("click", handleCloseModal), 0);
return () => window.removeEventListener("click", handleCloseModal);
}, [handleCloseModal]);
// 2022/04/16 - ์ถ์ฒ ํค์๋ ํจ์น - by 1-blue
const { data: recommendKeywords } = useSWR<IResponseOfRecommendKeywords>(
debounce && keyword ? `/api/keyword/${keyword}` : null
);
Author And Source
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(๐ ์ถ์ฒ ๊ฒ์์ด ๊ธฐ๋ฅ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://velog.io/@1-blue/์ถ์ฒ-๊ฒ์์ด-๊ธฐ๋ฅ์ ์ ๊ท์: ์์์ ์ ๋ณด๊ฐ ์์์ URL์ ํฌํจ๋์ด ์์ผ๋ฉฐ ์ ์๊ถ์ ์์์ ์์ ์ ๋๋ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค