← Назад к вопросам
Как оптимизировать отправку запроса из поисковой строки на стороне пользователя?
2.2 Middle🔥 111 комментариев
#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Оптимизация поисковых запросов
Поисковая строка - это классический case, где нужно оптимизировать количество запросов к серверу. Если просто отправлять запрос при каждом изменении input, получишь катастрофу с производительностью и нагрузкой на сервер.
Debouncing - основной инструмент
// hooks/useDebounce.ts
import { useState, useEffect } from 'react';
export function useDebounce<T>(value: T, delay: number = 300): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
Этот хук откладывает обновление значения на заданное время (обычно 300-500ms). Пока пользователь печатает, таймер перезапускается, и запрос отправляется только когда пользователь остановился.
Применение в компоненте поиска
// components/SearchQuestions.tsx
import { useState, useCallback } from 'react';
import { useDebounce } from '@/hooks/useDebounce';
import { fetchAPI } from '@/lib/api';
interface SearchResult {
id: string;
title: string;
profession_id: string;
}
export function SearchQuestions() {
const [input, setInput] = useState('');
const [results, setResults] = useState<SearchResult[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
const debouncedInput = useDebounce(input, 300);
useEffect(() => {
if (!debouncedInput.trim()) {
setResults([]);
return;
}
const fetchResults = async () => {
try {
setLoading(true);
const data = await fetchAPI<SearchResult[]>('/api/v1/questions/search', {
params: { q: debouncedInput },
});
setResults(data);
} catch (err) {
setError(err instanceof Error ? err : new Error('Search failed'));
} finally {
setLoading(false);
}
};
fetchResults();
}, [debouncedInput]);
return (
<div className="flex flex-col gap-4">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Поиск вопросов..."
className="border border-border-default rounded-lg px-4 py-2"
/>
{loading && <p className="text-content-secondary">Поиск...</p>}
{error && <p className="text-red-500">Ошибка: {error.message}</p>}
<ul className="space-y-2">
{results.map((result) => (
<li key={result.id} className="p-3 bg-surface-secondary rounded">
{result.title}
</li>
))}
</ul>
</div>
);
}
Дополнительные оптимизации
// Кэширование результатов
const searchCache = new Map<string, SearchResult[]>();
async function searchWithCache(query: string) {
if (searchCache.has(query)) {
return searchCache.get(query);
}
const results = await fetchAPI<SearchResult[]>('/api/v1/questions/search', {
params: { q: query },
});
searchCache.set(query, results);
return results;
}
// Отмена предыдущих запросов (AbortController)
let abortController: AbortController | null = null;
const fetchResults = async () => {
if (abortController) {
abortController.abort();
}
abortController = new AbortController();
try {
const data = await fetch('/api/v1/questions/search', {
signal: abortController.signal,
params: { q: debouncedInput },
});
} catch (err) {
if (err instanceof DOMException && err.name === 'AbortError') {
return;
}
setError(err);
}
};
Минимальная длина запроса
// Не отправляй запрос для очень коротких строк
if (debouncedInput.length < 2) {
setResults([]);
return;
}
Правильная оптимизация поиска - это комбинация debouncing, кэширования, отмены старых запросов и минимальной длины поиска. Так получаешь быстрый, отзывчивый интерфейс без перегруза серверных ресурсов.