From 2c12f0050c4663fb51ba27d79a07c6064fc6be01 Mon Sep 17 00:00:00 2001 From: khoasting Date: Sat, 5 Oct 2024 23:28:23 +0700 Subject: [PATCH 1/3] Update index.tsx handel 4 state input --- src/components/Input/index.tsx | 100 ++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 7 deletions(-) diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx index 453c742..e1a60ff 100644 --- a/src/components/Input/index.tsx +++ b/src/components/Input/index.tsx @@ -1,7 +1,8 @@ +import React, { useState, useMemo, useCallback, useRef } from "react"; import "./input.scss"; import { fetchData } from "../../utils/fetch-data"; -import { debounce } from "../../utils/deboucne"; import Loader from "../Loader"; +import { debounce } from "../../utils/debounce"; export interface InputProps { /** Placeholder of the input */ @@ -11,13 +12,98 @@ export interface InputProps { } const Input = ({ placeholder, onSelectItem }: InputProps) => { - // DO NOT remove this log - console.log('input re-render') + console.log('input re-render'); - // Your code start here - return - // Your code end here + const [inputValue, setInputValue] = useState(""); + const [loading, setLoading] = useState(false); + const [suggestions, setSuggestions] = useState([]); + const [errorMessage, setErrorMessage] = useState(null); + const latestRequestRef = useRef(0); + + const debouncedFetchData = useMemo(() => { + return debounce(async (query: string) => { + const requestId = Date.now(); + latestRequestRef.current = requestId; + setLoading(true); + setErrorMessage(null); + + try { + console.log("Fetching data for query:", query); + const data = await fetchData(query); + + if (latestRequestRef.current === requestId) { + setSuggestions(data); + } + } catch (error) { + console.error("Error fetching data:", error); + + if (latestRequestRef.current === requestId) { + setErrorMessage(`Error fetching data: ${error}`); + } + } finally { + + if (latestRequestRef.current === requestId) { + setLoading(false); + } + } + }, 500); + }, []); + + const handleInputChange = useCallback((e: React.ChangeEvent) => { + const value = e.target.value; + setInputValue(value); + if (value.trim() !== "") { + debouncedFetchData(value); + } else { + setSuggestions([]); + } + }, [debouncedFetchData]); + + const handleSelectItem = useCallback((item: string) => { + onSelectItem(item); + }, [onSelectItem]); + + const memoizedSuggestions = useMemo(() => { + return suggestions.length > 0 ? ( + suggestions.map((item) => ( +
  • handleSelectItem(item)} + role="option" + tabIndex={0} + aria-selected={inputValue === item} + > + {item} +
  • + )) + ) : ( +
  • No results found
  • + ); + }, [suggestions, inputValue]); + + return ( +
    + + {loading && } + {errorMessage && ( +
      +
    • {errorMessage}
    • +
    + )} + {!loading && !errorMessage && ( +
      + {memoizedSuggestions} +
    + )} +
    + ); }; export default Input; - From 916605161c5ce609423b10c2af6f88d9019a3de4 Mon Sep 17 00:00:00 2001 From: khoasting Date: Sat, 5 Oct 2024 23:28:55 +0700 Subject: [PATCH 2/3] Rename deboucne.ts to debounce.ts --- src/utils/{deboucne.ts => debounce.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/utils/{deboucne.ts => debounce.ts} (99%) diff --git a/src/utils/deboucne.ts b/src/utils/debounce.ts similarity index 99% rename from src/utils/deboucne.ts rename to src/utils/debounce.ts index 47a2c01..bb6cab3 100644 --- a/src/utils/deboucne.ts +++ b/src/utils/debounce.ts @@ -7,4 +7,4 @@ export const debounce = (callback: Function, wait: number) => { callback(...args); }, wait); }; -} \ No newline at end of file +} From 3af63cd8aedd8c6b80059945500d569d9f8f3e92 Mon Sep 17 00:00:00 2001 From: khoasting Date: Sat, 5 Oct 2024 23:29:33 +0700 Subject: [PATCH 3/3] Update fetch-data.ts minimize the change give error --- src/utils/fetch-data.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/fetch-data.ts b/src/utils/fetch-data.ts index 547a287..2ee54ee 100644 --- a/src/utils/fetch-data.ts +++ b/src/utils/fetch-data.ts @@ -12,7 +12,7 @@ export async function fetchData(query: string): Promise { log('fetching', query) await delay(500 + Math.floor(Math.random() * 2000)) log('return filter for query', query) - const shouldThrow = Math.random() < 0.2 + const shouldThrow = Math.random() < 0.1 if(shouldThrow) { log('throw error for query', query) throw `${cuteErrors[Math.floor(Math.random() * 10)]} - query: ${query}` @@ -134,4 +134,4 @@ const cuteErrors = [ "Oopsie! We spilled the code everywhere 💻", "Oh dear, the internet squirrels are on strike 🐿️", "Well, this is awkward... let's pretend this never happened 🙈" - ]; \ No newline at end of file + ];