React에서 검색 기능을 구현할 때 사용자가 입력 상자에 입력할 때마다 onChange 핸들러가 검색 기능을 호출합니다. 이 접근 방식은 특히 API를 호출하거나 데이터베이스를 쿼리하는 경우 성능 문제를 일으킬 수 있습니다. 검색 기능을 자주 호출하면 웹 서버에 과부하가 걸려 충돌이 발생하거나 UI가 응답하지 않을 수 있습니다. 디바운싱은 이 문제를 해결합니다.
디바운싱이란 무엇인가요?
React에서 검색 기능을 구현할 때 일반적으로 아래 그림과 같이 키 입력 시마다 onChange 핸들러 함수를 호출합니다:
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
이 방식을 구현하면 키 입력 시마다 검색 결과를 업데이트하기 위해 서버에 자주 요청을 보내야 하므로 비용이 많이 발생할 수 있습니다. 예를 들어, ‘webdev’를 검색할 때 시스템은 ‘w’, ‘we’, ‘web’ 문자가 포함된 요청을 여러 번 생성할 수 있습니다.
디바운싱은 사용자의 마지막 입력 이후 할당된 간격이 경과할 때까지 함수 실행을 연기하는 것을 포함합니다. 디바운스 기능을 활용하면 사용자가 계속 입력하는 동안 검색 핸들러를 반복적으로 호출하지 않아도 됩니다. 대신 지정된 지연 시간 동안 기다렸다가 핸들러를 한 번 호출합니다. 이 기간 동안 사용자가 계속 데이터를 입력하면 타이머가 재설정되어 핸들러를 다시 호출하기 전에 한 번 더 대기하게 됩니다. 사용자가 입력을 일시 중지하지 않는 한 이 주기는 지속됩니다.
디바운싱은 사용자가 데이터 입력을 중단할 때까지 작업을 지연시켜 불필요한 검색 쿼리를 최소화하고 요청을 필수 요청으로만 제한하여 애플리케이션의 서버 부하를 완화하는 것을 포함합니다.
React에서 검색을 디바운스하는 방법
디바운싱 메커니즘을 구현할 때 고려할 수 있는 여러 라이브러리 옵션이 있습니다. 또는 자바스크립트에 내장된 setTimeout 및 clearTimeout 함수를 활용하여 이 기능을 독립적으로 개발할 수도 있습니다.
본 텍스트는 Lodash 라이브러리에서 제공하는 디바운싱 기능을 사용합니다.
먼저 정상적으로 작동하는 React 애플리케이션을 가지고 있다고 가정해 보겠습니다. 이 경우 “Search”라는 이름의 새로운 엘리먼트를 개발하는 것이 현명할 것입니다. 그러나 현재 상황이 그렇지 않아서 작동하는 React 프로젝트가 없는 경우, 존경받는 “React 앱 생성” 도구를 사용하여 프로젝트를 생성하는 것이 좋습니다.
검색 컴포넌트 파일에 기능적인 검색 입력 상자를 구현하려면 제공된 코드 스니펫을 통합하여 키를 누를 때마다 지정된 핸들러 함수를 트리거할 수 있습니다.
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
마지막 이벤트가 발생한 후 지정된 기간 동안 호출을 지연시켜 `handleSearch` 함수의 실행을 완화하기 위해, Lodash 라이브러리에서 제공하는 `debounce` 함수를 활용할 수 있습니다. 이렇게 하면 함수가 필요 이상으로 자주 호출되지 않고 애플리케이션의 잠재적인 성능 문제를 방지할 수 있습니다.
import debounce from "lodash.debounce";
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 1000);
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
디바운스 함수는 핸들서치 함수와 같은 특정 함수에 미리 정해진 시간(예: 500ms)을 밀리초 단위로 지정하여 실행 속도를 제어할 수 있습니다.
앞서 언급한 코드는 사용자가 키 입력을 중단할 때까지 `handleSearch` 함수 호출을 보류하도록 설계되었습니다. 하지만 이 접근 방식은 React의 범위 내에서 의도한 대로 작동하지 않습니다. 다음 섹션에서는 이 함수가 작동하지 않는 이유를 설명하겠습니다.
디바운싱 및 리렌더링
본 애플리케이션은 시스템의 상태가 검색 인터페이스 내에 입력된 값을 규제하는 규제 입력을 사용합니다. 구체적으로, 개인이 지정된 필드에 데이터를 입력하면 React는 그에 따라 시스템의 상태를 업데이트합니다.
React는 개발자가 재사용 가능한 UI 컴포넌트를 만들 수 있는 사용자 인터페이스를 구축하는 데 사용되는 자바스크립트 라이브러리입니다. React에서 컴포넌트의 상태 값이 변경될 때마다 기본적으로 전체 컴포넌트가 다시 렌더링되고 그 안에 있는 모든 함수가 다시 실행됩니다. 이 프로세스를 통해 컴포넌트의 상태에 대한 업데이트나 수정 사항이 개발자의 추가 작업 없이도 화면에 즉시 반영됩니다.
앞서 언급한 검색 요소는 React 영역 내에서 반복적인 렌더링 프로세스를 거치는데, 이 과정에서 디바운싱 메커니즘이 적용됩니다. 구체적으로, 렌더링이 반복될 때마다 디바운스 기능이 작동하여 지연 기간과 시스템 메모리에 이미 존재하는 다른 지연 기간을 모두 모니터링하는 시간 추적 장치를 새로 생성합니다. 새로 설정된 타이머는 미리 정해진 간격으로 시간이 경과하면 검색 작업의 실행을 트리거하는 반면, 이전 타이머는 할당된 기간이 완전히 소진될 때까지 계속 유지됩니다. 따라서 프로세스가 연속적으로 반복될 때마다 새로운 타이머가 생성되고, 이전 타이머가 종료된 후 원하는 검색 기능이 호출됩니다. 본질적으로 실제
는 컴포넌트에 외부적으로 디바운싱 메커니즘을 적용하거나 컴포넌트 자체 내에서 메모화 방법론을 활용합니다.이렇게 하면 컴포넌트가 다시 렌더링되는지 여부와 상관없이 React는 디바운스된 함수를 반복적으로 실행하지 않습니다.
검색 컴포넌트 외부에서 디바운스 함수 정의하기
다음 예시와 같이 ‘디바운스’ 함수를 검색 컴포넌트의 경계 밖으로 재배치했습니다:
import debounce from "lodash.debounce"
const handleSearch = (searchTerm) => {
console.log("Search for:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 500);
현재 애플리케이션 설계 프로세스의 반복 작업에서 `debounceSearch`라는 함수를 검색 컴포넌트의 아키텍처 내에 통합하기로 결정했습니다. 이 작업에는 입력 검색 쿼리를 `debouncedSearch` 메서드에 인수로 제공하는 것이 포함됩니다.
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
지정된 시간 간격이 만료되면 정보를 찾아서 검색하는 기능이 활성화됩니다.
디바운스 함수 메모화
메모화란 특정 함수에 의해 생성된 출력을 메모리에 저장하는 개념으로, 동일한 입력 파라미터를 가진 함수에 대한 후속 호출 시 새로 계산하는 데 연산 자원을 소비하지 않고 캐시에서 미리 계산된 결과를 검색하여 보다 효율적으로 서비스를 제공할 수 있습니다.
디바운스된 함수의 메모화를 구현할 때는 `useMemo` 훅을 활용하는 것이 좋습니다.
import debounce from "lodash.debounce";
import { useCallback, useMemo, useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = useCallback((searchTerm) => {
console.log("Search for:", searchTerm);
}, []);
const debouncedSearch = useMemo(() => {
return debounce(handleSearch, 500);
}, [handleSearch]);
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
이 코드는 사용Callback 훅을 활용하여 React가 handleSearch 함수를 한 번만 실행하도록 보장합니다. 이 후크가 없다면 렌더링을 다시 할 때마다 사용메모 후크에 대한 의존성 목록이 변경되어 의도치 않게 디바운스 함수가 호출될 수 있기 때문에 이 점이 중요합니다.
React는 핸들서치 함수 또는 관련 지연 기간에 수정이 있는 경우에만 디바운스된 함수를 호출해야 합니다.
디바운스로 검색 최적화
때때로 속도를 조절하면 효율성 측면에서 더 나은 결과를 얻을 수 있습니다. 비용이 많이 드는 데이터베이스 또는 API 쿼리가 관련된 상황에서는 디바운스 기능을 활용하는 것이 최적의 전략이 될 수 있습니다. 기본적으로 이 함수는 요청을 백엔드로 전달하기 전에 일시적으로 일시 중지합니다.
이 기능을 구현하면 미리 정해진 일시 중지 시간이 경과하고 입력 중단이 감지될 때까지 전송을 연기하여 서버로 전송되는 요청의 빈도를 줄일 수 있습니다. 따라서 서버가 과도한 요청에 압도되는 것을 방지하여 최적의 운영 효율성을 유지할 수 있습니다.