umc 6주차 과제중 Debounce와 Throttling이라는 개념을 배웠다!
Debounce : 연속된 이벤트 호출을 제한하여 마지막 이벤트만 처리하도록 하는 기술
→ 연속된 이벤트가 발생할 때마다 타이머를 리셋하고, 일정 시간이 지난 후에 이벤트를 처리
- Debounce는 주로 어디에 사용하나요?ex) 검색어 자동 완성 기능에서 사용자가 입력을 멈춘 후에만 서버에 요청을 보냄
- 사용자 입력 필드에서 입력이 끝난 후 일정 시간 동안 입력이 없을 때만 서버에 요청을 보내는 경우
적용 과정
1. debounce hook 만들기
2. 적용하기
1. useDebounce.js hook 구현
import { useState, useEffect } from "react";
export const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
이 훅은 입력된 값이 일정 시간 동안 변경되지 않을 때까지 기다렸다가 업데이트된다.
사용자가 입력할 때마다 API 호출을 하지 않도록 도와주는 기능을 한다. 이 기능이 바로 debounce!
⭐️시간 차를 두기⭐️
- value: 디바운스 처리할 값, 검색어 넣으면 됨
- delay: 디바운스 대기 시간(밀리초)
- useEffect: value가 변경될 때마다 타이머를 설정한다. 설정된 시간이 지나면 debouncedValue를 업데이트 한다. 타이머가 설정되는 동안 value가 다시 변경되면 이전 타이머는 취소된다.
2. 기존 search 페이지에 추가
기존 search 페이지 코드
import { useCallback, useEffect, useState } from "react";
import {
StyleSearch,
StyleTitle,
StyledInput,
StyledMovieCard,
StyledMovieList,
StyledSearchView,
Poster,
Overview,
Title,
Star,
} from "./Search.style";
import axios from "axios";
export const Search = () => {
const [searchTerm, setSearchTerm] = useState("");
const [movies, setMovies] = useState([]);
const apiKey = "d2cb276ab0ca7b65595d1e9a2fd4ea84";
const handleSearch = useCallback(async () => {
if (searchTerm) {
try {
const response = await axios.get(
`https://api.themoviedb.org/3/search/movie`,
{
params: {
api_key: apiKey,
query: searchTerm,
},
}
);
setMovies(response.data.results);
} catch (error) {
console.error("Error fetching movies:", error);
}
}
}, [searchTerm]);
useEffect(() => {
handleSearch();
}, [handleSearch]);
const calculateStars = (vote_average) => {
const stars = Math.round(vote_average);
return stars > 0 ? Array(stars).fill("⭐").join("") : "";
};
return (
<StyleSearch>
<StyleTitle>🎥 Find your movies!</StyleTitle>
<StyledInput
type="text"
placeholder="Type to search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<StyledSearchView>
<StyledMovieList>
{searchTerm &&
movies.map((movie) => (
<StyledMovieCard key={movie.id}>
<Poster
src={`https://image.tmdb.org/t/p/w200${movie.poster_path}`}
alt={`Movie Poster of ${movie.title}`}
/>
<Title>{movie.title}</Title>
<Star>{`Rating: ${calculateStars(movie.vote_average)}`}</Star>
<Overview>
<p>{movie.overview || "No overview available."}</p>
</Overview>
</StyledMovieCard>
))}
</StyledMovieList>
</StyledSearchView>
</StyleSearch>
);
};
useDebounce 훅을 추가한 search 페이지 코드
import { useCallback, useEffect, useState } from "react";
import {
StyleSearch,
StyleTitle,
StyledInput,
StyledMovieCard,
StyledMovieList,
StyledSearchView,
Poster,
Overview,
Title,
Star,
} from "./Search.style";
import axios from "axios";
import { useDebounce } from "../../hooks/useDebounce";
export const Search = () => {
const [searchTerm, setSearchTerm] = useState("");
const [movies, setMovies] = useState([]);
const apiKey = "d2cb276ab0ca7b65595d1e9a2fd4ea84";
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const handleSearch = useCallback(async () => {
if (debouncedSearchTerm) {
try {
const response = await axios.get(
`https://api.themoviedb.org/3/search/movie`,
{
params: {
api_key: apiKey,
query: debouncedSearchTerm,
},
}
);
setMovies(response.data.results);
} catch (error) {
console.error("Error fetching movies:", error);
}
} else {
setMovies([]);
}
}, [debouncedSearchTerm]);
useEffect(() => {
handleSearch();
}, [handleSearch]);
const calculateStars = (vote_average) => {
const stars = Math.round(vote_average);
return stars > 0 ? Array(stars).fill("⭐").join("") : "";
};
return (
<StyleSearch>
<StyleTitle>🎥 Find your movies!</StyleTitle>
<StyledInput
type="text"
placeholder="Type to search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<StyledSearchView>
<StyledMovieList>
{debouncedSearchTerm &&
movies.map((movie) => (
<StyledMovieCard key={movie.id}>
<Poster
src={`https://image.tmdb.org/t/p/w200${movie.poster_path}`}
alt={`Movie Poster of ${movie.title}`}
/>
<Title>{movie.title}</Title>
<Star>{`Rating: ${calculateStars(movie.vote_average)}`}</Star>
<Overview>
<p>{movie.overview || "No overview available."}</p>
</Overview>
</StyledMovieCard>
))}
</StyledMovieList>
</StyledSearchView>
</StyleSearch>
);
};
기존 코드에
const debouncedSearchTerm = useDebounce(searchTerm, 500);
이렇게 검색할 값과 시간을 추가해준다
기존 api를 가져오던 useEffect 훅에서 쿼리 값을 추가한 훅으로 변경해준다
조건문과 의존성 배열도 seatchTerm => 추가한 훅으로 변경하기!
이런식으로~~
실행을 보면 무슨 차이인지 감이 딱 온다!
수정 전
수정 후
사용자가 입력을 할 때마다 API 요청이 아닌 시간 차를 두어서 api 요청을 하는 것이 바로 debounce!
재밋당
728x90
'React' 카테고리의 다른 글
[React/리액트] usestate 남발 코드를 react-hook-form로 리팩토링 하기 (0) | 2024.06.25 |
---|---|
[React] 리액트 무한스크롤 예제 및 동작 과정 설명 (1) | 2024.05.27 |
[React] 리액트 상태 업데이트 할 때 update function 사용하기 (0) | 2024.05.05 |
리액트 프리온보딩 사전 과제 질문 (0) | 2024.03.01 |
[React] 리액트 Redux를 사용해 todo list 만들기 (1) | 2024.03.01 |