๐ฅ AbortController
abortSiganl๊ฐ์ฒด ์ธํฐํ์ด์ค๋ฅผ ๋ฐํํ๋ค. (์ฝ๊ธฐ ์ ์ฉ) ํด๋น signal ์ ๋คํธ์ํฌ ์์ฒญ์ ๊ฐ์ด ๋ด์์ ์ทจ์ํ ์ ์๋ ์ญํ ์ ๋ด๋นํ๋ค.input์ ๊ฐ์ด ์ ๋ ฅ๋ ๋๋ง๋ค ๊ฒ์๊ฒฐ๊ณผ๊ฐ ๋์ค๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ณ ์ ํ๋ค. ํ์ง๋ง onChange๊ฐ ์ด๋ฃจ์ด์ง ๋๋ง๋ค ์๋ฒ๋ก ์์ฒญ์ ๋ณด๋ด๋ฉด 2๊ฐ์ง ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
Debounce๋ ์ ๋ฒ ๊ฒ์๊ธ์์ ๊ตฌํ์ ํด๋ณด์์ผ๋ ์ด๋ฒ์๋ Abort Controller๋ฅผ ํตํด 1๋ฒ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด๋ณธ๋ค...!
useAbort Hooks๋ฅผ ์์ฑํ๋ค.
// useAbort.ts
import { useEffect, useState } from "react";
import { ICharacter } from "./types";
interface IUseAbort {
data: ICharacter[];
isLoading: boolean;
error: Error | null;
}
const useAbort = (keyword: string): IUseAbort => {
const [data, setData] = useState<ICharacter[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// ๊ฒ์์ด์ ๊ธธ์ด๊ฐ 0์ด๋ผ๋ฉด ์คํํ์ง ์๋๋ค.
if (keyword.length === 0) return;
// abortController ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
let abortController = new AbortController();
const fetchData = async () => {
try {
const response = await fetch(
`https://swapi.dev/api/people?search=${keyword}`,
// signal์ ์ ๋ฌํ๋ค.
{ signal: abortController.signal }
).then((res) => res.json());
setIsLoading(false);
setData(response.results);
} catch (error: any) {
if (error.name === "AbortError") {
setError(error);
setIsLoading(false);
}
}
};
fetchData();
return () => {
// ํด๋ฆฐ์
ํจ์๋ก ์์ฒญ์ ์ทจ์ํ๋ abort()๋ฅผ ์คํํ๋ค.
// ์ด๋ ์๋ต์ด ์ค๊ธฐ ์ ์ ์ด hooks๊ฐ ์ฌ์คํ๋๋ฉด ํ์ฌ ์งํ์ค์ธ ์์ฒญ์ ์ทจ์ํ๋ ์ญํ ์ ํ๋ค.
abortController.abort();
};
}, [keyword]);
return { data, isLoading, error };
};
export default useAbort;
์ฌ์ฉ
// App.tsx
import React, { useCallback, useState } from "react";
import useAbort from "./useAbort";
function App() {
const [keyword, setKeyword] = useState("");
const { data } = useAbort(keyword);
// keyword๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค useAbort๊ฐ ์คํ๋๋ค.
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
setKeyword(e.target.value);
}, []);
return (
<div className="App">
<form>
<input type="text" onChange={handleChange} value={keyword} />
</form>
<ul>
{data?.map((item, i) => (
<li key={i}>{item.name}</li>
))}
</ul>
</div>
);
}
export default App;