a tool for shared writing and social publishing

fix fetching tags and simplify result rendering

+16 -21
+16 -21
components/Tags.tsx
··· 1 1 "use client"; 2 2 import { CloseTiny } from "components/Icons/CloseTiny"; 3 3 import { Input } from "components/Input"; 4 - import { useState, useRef, useEffect } from "react"; 4 + import { useState, useRef } from "react"; 5 + import { useDebouncedEffect } from "src/hooks/useDebouncedEffect"; 5 6 import { Popover } from "components/Popover"; 6 7 import Link from "next/link"; 7 8 import { searchTags, type TagSearchResult } from "actions/searchTags"; ··· 81 82 let inputWidth = placeholderInputRef.current?.clientWidth; 82 83 83 84 // Fetch tags whenever the input value changes 84 - useEffect(() => { 85 - let cancelled = false; 86 - setIsSearching(true); 87 - 88 - searchTags(tagInputValue).then((results) => { 89 - if (!cancelled && results) { 85 + useDebouncedEffect( 86 + async () => { 87 + setIsSearching(true); 88 + const results = await searchTags(tagInputValue); 89 + if (results) { 90 90 setSearchResults(results); 91 - setIsSearching(false); 92 91 } 93 - }); 94 - 95 - return () => { 96 - cancelled = true; 97 - }; 98 - }, [tagInputValue]); 92 + setIsSearching(false); 93 + }, 94 + 300, 95 + [tagInputValue], 96 + ); 99 97 100 98 const filteredTags = searchResults.filter( 101 99 (tag) => !props.selectedTags.includes(tag.name), ··· 140 138 } 141 139 }; 142 140 143 - const [userInputResult, setUserInputResult] = useState(false); 144 - useEffect(() => { 145 - const isTopResultShowing = 146 - tagInputValue !== "" && 147 - !filteredTags.some((tag) => tag.name === tagInputValue); 148 - setUserInputResult(isTopResultShowing); 149 - }, [tagInputValue, filteredTags]); 141 + const userInputResult = 142 + tagInputValue !== "" && 143 + !filteredTags.some((tag) => tag.name === tagInputValue); 144 + 150 145 return ( 151 146 <div className="relative"> 152 147 <Input