자바스크립트
검색어를 입력할 때마다 바로 검색을 실행하면 서버 자원이 낭비될 수 있습니다. 이를 방지하기 위해 다음과 같은 방법을 사용할 수 있습니다:
- 디바운싱(Debouncing): 사용자가 입력을 멈춘 후 일정 시간 동안 대기한 다음 검색 요청을 보내는 방법입니다.
- 스로틀링(Throttling): 일정 시간 간격으로만 검색 요청을 보내는 방법입니다.
일반적으로 디바운싱이 검색에 더 자주 사용됩니다. 이는 사용자가 입력을 멈춘 후에만 검색 요청을 보내기 때문입니다.
디바운싱을 사용한 예제
아래는 JavaScript와 디바운싱을 사용하여 검색 요청을 효율적으로 처리하는 예제입니다
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Search with Debouncing</title>
</head>
<body>
<input type="text" id="searchInput" placeholder="Search...">
<div id="results"></div>
<script>
// 디바운스 함수
function debounce(func, delay) {
let debounceTimer;
return function(...args) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => func.apply(this, args), delay);
};
}
// 검색 함수
async function search(query) {
if (!query) return;
try {
const response = await fetch(`/search?q=${encodeURIComponent(query)}`);
const data = await response.json();
displayResults(data);
} catch (error) {
console.error('Error fetching search results:', error);
}
}
// 결과 표시 함수
function displayResults(data) {
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
data.results.forEach(result => {
const resultItem = document.createElement('div');
resultItem.textContent = result;
resultsDiv.appendChild(resultItem);
});
}
// 디바운스를 적용한 검색 함수
const debouncedSearch = debounce(search, 300);
// 입력 이벤트 리스너
document.getElementById('searchInput').addEventListener('input', (event) => {
debouncedSearch(event.target.value);
});
</script>
</body>
</html>
설명
- 디바운스 함수: debounce 함수는 입력이 멈춘 후 일정 시간(delay) 동안 대기한 다음에 지정된 함수를 실행합니다. 입력이 계속되면 타이머를 재설정합니다.
- 검색 함수: search 함수는 실제로 검색 요청을 서버에 보냅니다.
- 결과 표시 함수: displayResults 함수는 서버에서 받은 검색 결과를 화면에 표시합니다.
- 디바운스를 적용한 검색 함수: debouncedSearch는 debounce 함수를 사용하여 search 함수에 디바운싱을 적용한 것입니다.
- 입력 이벤트 리스너: input 이벤트가 발생할 때마다 debouncedSearch 함수를 호출합니다.
이 방법을 사용하면 사용자가 입력을 멈춘 후에만 검색 요청이 발생하므로, 불필요한 서버 요청을 줄일 수 있습니다.
리액트-
하드처리
리액트에서 검색어 입력 시 디바운싱을 적용하여 서버 자원 낭비를 줄이는 방법을 설명하겠습니다. 이 예제에서는 useState와 useEffect 훅을 사용하여 상태를 관리하고, useCallback 훅을 사용하여 디바운스 함수를 생성합니다.
React 컴포넌트 예제
아래는 디바운싱을 적용한 React 컴포넌트의 예제입니다:
import React, { useState, useEffect, useCallback } from 'react';
function debounce(func, wait) {
let timeout;
return function(...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
const SearchComponent = () => {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
// 디바운스된 검색 함수
const debouncedSearch = useCallback(
debounce(async (searchQuery) => {
if (!searchQuery) return;
try {
const response = await fetch(`/search?q=${encodeURIComponent(searchQuery)}`);
const data = await response.json();
setResults(data.results);
} catch (error) {
console.error('Error fetching search results:', error);
}
}, 300), // 300ms 디바운스 시간
[]
);
// query 상태가 변경될 때마다 debouncedSearch 호출
useEffect(() => {
debouncedSearch(query);
}, [query, debouncedSearch]);
// 입력 핸들러
const handleInputChange = (event) => {
setQuery(event.target.value);
};
return (
<div>
<input
type="text"
value={query}
onChange={handleInputChange}
placeholder="Search..."
/>
<div>
{results.map((result, index) => (
<div key={index}>{result}</div>
))}
</div>
</div>
);
};
export default SearchComponent;
설명
- 디바운스 함수: debounce 함수는 입력이 멈춘 후 일정 시간(wait)이 지난 다음에 주어진 함수를 호출합니다. useCallback을 사용하여 메모이제이션된 디바운스 함수를 생성합니다.
- 상태 관리: query와 results 상태를 관리합니다. query는 입력된 검색어를, results는 검색 결과를 저장합니다.
- 검색 함수: debouncedSearch 함수는 디바운싱을 적용하여 서버에 검색 요청을 보냅니다.
- useEffect 훅: query 상태가 변경될 때마다 debouncedSearch 함수를 호출합니다. debouncedSearch 함수는 디바운싱을 적용하여 서버 요청을 최적화합니다.
- 입력 핸들러: handleInputChange 함수는 입력값이 변경될 때마다 query 상태를 업데이트합니다.
- 렌더링: input 태그와 검색 결과를 표시하는 div 태그를 렌더링합니다. results 배열을 맵핑하여 각 결과를 화면에 출력합니다.
이 방법을 사용하면 검색어 입력 시 디바운싱을 적용하여 서버 요청 빈도를 줄이고, 효율적인 검색 기능을 구현할 수 있습니다.
리액트 - lodash 이용
React와 TypeScript에서 lodash의 debounce 함수를 사용하여 디바운싱을 구현하는 코드를 다시 정리하겠습니다.
1. lodash 설치
먼저, lodash와 해당 타입 정의 파일을 설치합니다. 프로젝트 루트 디렉토리에서 다음 명령어를 실행합니다:
npm install lodash npm install @types/lodash npm install --save-dev @types/lodash
2. React 컴포넌트 코드
updateItem 함수에 디바운스를 적용한 전체 코드는 다음과 같습니다:
import React, { useCallback, useEffect, useState } from "react";
import "./App.css";
import Todo, { ItemType } from "./components/Todo";
import { Container, List, Paper } from "@mui/material";
import AddTodo from "./components/AddTodo";
import Call from "./service/ApiService";
import { debounce } from "lodash";
const DUMMY_DATA = [
{
todoId: "0",
title: "Todo 컴포넌트 만들기",
done: false,
},
{
todoId: "1",
title: "Todo 컴포넌트 만들기2",
done: false,
},
{
todoId: "2",
title: "Todo 컴포넌트 만들기3",
done: false,
},
];
const App: React.FC = () => {
const [items, setItems] = useState<ItemType[]>([]);
const [errorMessage, setErrorMessage] = useState<string>("");
const requestOptions = {
method: "GET",
headers: {
"Content-Type": "application/json",
},
};
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(
"http://localhost:5000/api/todo",
requestOptions
);
if (response.ok) {
const res = await response.json();
setItems(res.data);
} else {
console.error("Failed to fetch data");
}
} catch (error) {
console.error(" 에러 :", error);
setErrorMessage("데이터를 가져오지 못했습니다.");
}
};
fetchData();
}, []);
// 추가 처리
const addItem = (item: ItemType) => {
Call("/todo", "POST", item).then((response) => {
setItems(response.data);
});
};
// 삭제 처리
const deleteItem = (item: ItemType) => {
Call("/todo", "DELETE", item).then((response) => {
setItems(response.data);
});
};
// 디바운스 적용된 수정 처리 함수
const debouncedUpdateItem = useCallback(
debounce((item: ItemType) => {
Call("/todo", "PUT", item).then((response) => {
setItems(response.data);
});
}, 300),
[]
);
const updateItem = (item: ItemType) => {
debouncedUpdateItem(item);
};
let todoItems;
if (items && items.length > 0) {
todoItems = (
<Paper className="mt50">
<List>
{items.map((item) => (
<Todo
item={item}
key={item.todoId}
deleteItem={deleteItem}
updateItem={updateItem}
/>
))}
</List>
</Paper>
);
} else if (errorMessage) {
todoItems = <h3 className="mt50">{errorMessage}</h3>;
}
return (
<div className="App">
<Container maxWidth="md" className="mt5">
<AddTodo addItem={addItem} />
<div className="TodoList">{todoItems}</div>
</Container>
</div>
);
};
export default App;
설명
- lodash 설치: lodash와 해당 타입 정의 파일을 설치합니다.
- debounce 가져오기: import { debounce } from "lodash"; 구문을 사용하여 lodash에서 debounce 함수를 가져옵니다.
- 디바운스 적용된 수정 처리 함수: debouncedUpdateItem 함수는 debounce를 사용하여 생성됩니다. 이 함수는 300ms의 지연 시간을 가지며, 호출이 연속적으로 발생해도 마지막 호출 후 300ms가 지나야 실행됩니다.
- updateItem 함수: updateItem 함수는 debouncedUpdateItem을 호출하여 디바운스된 함수를 실행합니다.
- useCallback 사용: debouncedUpdateItem 함수는 useCallback을 사용하여 메모이제이션됩니다. 이렇게 하면 함수가 재생성되지 않고, 컴포넌트가 리렌더링되더라도 동일한 함수 인스턴스를 유지합니다.
- 렌더링: items 배열을 맵핑하여 각 Todo 컴포넌트를 렌더링합니다. Todo 컴포넌트는 item, deleteItem, updateItem props를 받습니다.
이 코드를 통해 updateItem 함수 호출 시 디바운싱이 적용되어 불필요한 서버 요청을 줄일 수 있습니다.














댓글 ( 0)
댓글 남기기