Debounce란
Debouncing is a technique in programming that helps improve the performance of web applications by controlling the frequency at which time-consuming tasks are triggered.
라고 적혀있다. 간단하게 말하면, 트리거가 계속 발동되어 성능 저하가 되는 것을 막기 위한 기술이다.
https://velog.io/@ekrtionl/React-loader-action-2-json
위 내용에서 이어서 작업했다.
먼저 useDebounce 훅을 작성했다. 검색 값과 delay 시간을 파라미터로 받아 이를 찾는 훅을 만들었다.
// useDebounce.js
import { useEffect, useState } from "react";
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
export default useDebounce;
사실 debounce에서 delay 시간만큼 기다렸다가 데이터를 fetch 후 해당 데이터를 넘기는 코드를 작성하는 것이 일반적인 것 같다. 하지만 내가 기존에 작성한 코드는 전체 데이터를 가져오기 때문에, 이후 input 창에 값을 입력하면 해당하는 데이터들을 filtering 하는 식으로 코드를 간단하게 작성했다.
// ArticlePage.jsx
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { Link, json, defer } from "react-router-dom";
import useDebounce from "../utils/useDebounce";
function ArticlesPage() {
const { data, isPending, isError, error } = useQuery({
queryKey: ["articles"],
queryFn: () =>
fetch("https://jsonplaceholder.typicode.com/posts").then((res) =>
res.json()
),
});
const [searchTerm, setSearchTerm] = useState("");
const debounceSearchTerm = useDebounce(searchTerm, 500);
let content;
if (isPending) {
content = <p>Loading!!!</p>;
}
if (isError) {
content = <p>error : {error.message}</p>;
}
if (data) {
const filteredData = data.filter((article) =>
article.title.toLowerCase().includes(debounceSearchTerm.toLowerCase())
);
content = (
<ol>
{filteredData.map((article) => (
<li key={article.id}>
<Link to={`${article.id}`}>{article.title}</Link>
</li>
))}
</ol>
);
// content = (
// <ol>
// {data.map((article) => (
// <li key={article.id}>
// <Link to={`${article.id}`}>{article.title}</Link>
// </li>
// ))}
// </ol>
// );
}
return (
<div>
<Link to={"new"}>New</Link>
<p>ArticlesPage</p>
<input
type='text'
placeholder='input'
onChange={(e) => setSearchTerm(e.target.value)}
/>
{content}
</div>
);
}
export default ArticlesPage;
async function loadArticles() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
console.log(response);
if (response.status !== 200) {
return json({ message: "POST 불러오기 실패" }, { status: 500 });
} else {
const resData = await response.json();
return resData;
}
}
export function loader() {
return defer({
articles: loadArticles(),
});
}
지금은 jsonplaceholder를 사용해서 간단한 API를 썼지만, 이후에는 직접 API를 만들어 더 좋은 코드를 작성할 예정이다.