| 537 | * — an emptied box should show everyone at once, not after a pause. |
| 538 | */ |
| 539 | const useDebouncedSearch = (): { |
| 540 | readonly typed: string; |
| 541 | readonly term: string; |
| 542 | readonly setTyped: (value: string) => void; |
| 543 | readonly clear: () => void; |
| 544 | } => { |
| 545 | const [typed, setTypedState] = useState(""); |
| 546 | const [term, setTerm] = useState(""); |
| 547 | |
| 548 | useEffect(() => { |
| 549 | if (typed === term) return; |
| 550 | const handle = setTimeout(() => setTerm(typed), SEARCH_DEBOUNCE_MS); |
| 551 | return () => clearTimeout(handle); |
| 552 | }, [typed, term]); |
| 553 | |
| 554 | return { |
| 555 | typed, |
| 556 | term, |
| 557 | setTyped: setTypedState, |
| 558 | clear: () => { |
| 559 | setTypedState(""); |
| 560 | setTerm(""); |
| 561 | }, |
| 562 | }; |
| 563 | }; |
| 564 | |
| 565 | function UserSearch(props: { |
| 566 | readonly value: string; |