diff --git a/.gitignore b/.gitignore
index 87b58f0..5eea626 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,5 @@ storybook-static
*.njsproj
*.sln
*.sw?
+*.history
+.vercel
diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx
index 453c742..9709187 100644
--- a/src/components/Input/index.tsx
+++ b/src/components/Input/index.tsx
@@ -1,7 +1,8 @@
import "./input.scss";
import { fetchData } from "../../utils/fetch-data";
import { debounce } from "../../utils/deboucne";
-import Loader from "../Loader";
+import { ChangeEvent, useCallback, useRef, useState } from "react";
+import { FETCHING_STATUS } from "../../utils/constants";
export interface InputProps {
/** Placeholder of the input */
@@ -10,12 +11,110 @@ export interface InputProps {
onSelectItem: (item: string) => void;
}
+const SearchResultList: React.FC<{
+ list: string[],
+ status: string | null,
+ onSelectItem: (item: string) => void}> = ({
+ list,
+ status,
+ onSelectItem
+ }) => {
+ if (status === FETCHING_STATUS.FETCHING) {
+ return
Loading...
;
+ }
+
+ if (status === FETCHING_STATUS.ERROR) {
+ return Occur an error.
+ }
+
+ if (!list.length && status !== FETCHING_STATUS.INITIAL) {
+ return No results.
+ }
+
+ if (list.length) {
+ return
+ }
+
+ return null;
+}
+
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
+ const [status, setStatus] = useState(FETCHING_STATUS.INITIAL);
+ const [list, setList] = useState([]);
+ const inputRef = useRef();
+ const fetchDataPromise = useRef>();
+
+ const _onChangeFnc = (e:ChangeEvent) => {
+ const { value } = e.target;
+
+ // Return when there is empty value.
+ if(!value.trim()) {
+ setList([]);
+ setStatus(FETCHING_STATUS.INITIAL);
+
+ return;
+ }
+
+ inputRef.current = value;
+ fetchDataPromise.current = undefined;
+
+ setStatus(FETCHING_STATUS.FETCHING);
+
+ // Fetch API.
+ const _fetchDataPromise = fetchData(value);
+ fetchDataPromise.current = _fetchDataPromise;
+
+ _fetchDataPromise
+ .then((res) => {
+ if (isCheckXhr(_fetchDataPromise)) {
+ setStatus(FETCHING_STATUS.INITIAL);
+ return;
+ }
+ setList(res);
+ setStatus(FETCHING_STATUS.SUCCESS);
+ })
+ .catch(() => {
+ if (isCheckXhr(_fetchDataPromise)) {
+ setStatus(FETCHING_STATUS.INITIAL);
+ return;
+ }
+ setList([]);
+ setStatus(FETCHING_STATUS.ERROR);
+ })
+ .finally(() => {
+ fetchDataPromise.current = undefined;
+ });
+ }
+
+ const isCheckXhr = (promise: Promise) => {
+ // Skip previous request.
+ return fetchDataPromise.current != promise;
+ }
+
+ const isChangeInputRef = (e: string) => {
+ const isChanged = e !== inputRef.current;
+
+ return isChanged;
+ }
+
+ const _onChangeDebounce = useCallback(
+ debounce(_onChangeFnc, 300),
+ []
+ );
+
+ return
+
+
+
// Your code end here
};
diff --git a/src/components/Input/input.scss b/src/components/Input/input.scss
index 1dafbe7..3b235ad 100644
--- a/src/components/Input/input.scss
+++ b/src/components/Input/input.scss
@@ -4,3 +4,25 @@
html{
font-size: 16px;
}
+
+.search-input {
+ &--text {
+ padding: 5px 10px;
+ }
+ &--list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ border: 1px solid #000;
+ border-top: none;
+ max-height: 350px;
+ overflow-y: auto;
+ &--item {
+ padding: 10px;
+ cursor: pointer;
+ &:hover {
+ background-color: antiquewhite;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
new file mode 100644
index 0000000..1078f4d
--- /dev/null
+++ b/src/utils/constants.ts
@@ -0,0 +1,6 @@
+export const FETCHING_STATUS = {
+ "INITIAL": "initial",
+ "FETCHING": "fetching",
+ "ERROR": "error",
+ "SUCCESS": "success"
+}
\ No newline at end of file