Как создать поисковую строку в React с фильтрацией в реальном времени

Поисковые строки помогают пользователям быстро находить нужный контент на сайте. Они также полезны для аналитики — по запросам видно, что ищут посетители.
React отлично подходит для реализации отзывчивой поисковой строки. С помощью хуков и методов массива filter/map вы получите поиск в реальном времени, который быстро реагирует на ввод.
Что понадобится
- Базовый проект React (create-react-app или другой).
- Понимание хуков useState и обработчиков событий onChange.
- Исходные данные — локальный массив или API.
Если у вас ещё нет проекта, создайте его командой:
npx create-react-app search-barБазовая форма ввода
Добавьте в файл App.js простую форму с input:
export default function App() {
return (
)
}Далее контролируйте значение input через состояние. Импортируйте useState и добавьте обработчик onChange:
import { useState } from 'react'
export default function App() {
const [query, setQuery] = useState('')
const handleChange = (e) => {
setQuery(e.target.value)
}
return (
)
}Каждый ввод обновляет состояние query через handleChange.
Фильтрация данных при вводе
По сути, поисковая строка должна фильтровать набор данных по введённому запросу. Удобно хранить и сам запрос, и отфильтрованный список в одном объекте состояния, чтобы уменьшить число рендеров:
const [state, setState] = useState({
query: '',
list: []
})Пример данных — список постов:
const posts = [
{
url: '',
tags: ['react', 'blog'],
title: 'How to create a react search bar',
},
{
url: '',
tags: ['node', 'express'],
title: 'How to mock api data in Node',
},
// more data here
]В обработчике onChange выполните фильтрацию и сохраните результаты в состоянии:
const handleChange = (e) => {
const value = e.target.value
const results = posts.filter(post => {
if (value === '') return true
return post.title.toLowerCase().includes(value.toLowerCase())
})
setState({
query: value,
list: results
})
}Заметьте: когда query пустой, мы возвращаем все элементы (или можно вернуть пустой список — зависит от UX). Приведение строк к нижнему регистру делает поиск нечувствительным к регистру.
Отображение результатов
Для вывода списка используйте map по state.list. Часто полезно скрывать результаты, пока query пустой:
export default function App() {
// state и handleChange
return (
{(state.query === '' ? '' : state.list.map(post => {
return - {post.title}
}))}
)
}Можно улучшить UX, показывая сообщение, если результатов нет:
{state.query === ''
? 'Введите запрос для поиска'
: (!state.list.length
? 'По вашему запросу ничего не найдено'
: state.list.map(post => - {post.title}
))}
Это помогает пользователю понять, что поиск выполнен и просто не дал совпадений.
Поиск по нескольким полям
В простейшем варианте мы ищем только по title. Чтобы расширить поиск на другие поля (например tags или url), используйте логический OR:
const results = posts.filter(post => {
const q = value.toLowerCase()
return (
post.title.toLowerCase().includes(q) ||
post.tags.join(' ').toLowerCase().includes(q) ||
(post.url && post.url.toLowerCase().includes(q))
)
})Так поиск станет более гибким и полезным для пользователей.
Альтернативные подходы
- Debounce вводов: используйте debounce (lodash или собственную реализацию), если фильтрация тяжёлая или идёт запрос на сервер. Это уменьшит число запросов и рендеров.
- Поиск на сервере: при больших наборах данных отправляйте запросы на сервер с query, чтобы сервер возвращал уже отфильтрованный список.
- Индексация и полнотекстовый поиск: для сложных сценариев используйте поисковые движки (Elasticsearch, Algolia, Typesense) или БД с полнотекстовым поиском.
- Использование библиотек UI: готовые компоненты (Downshift, react-select) облегчают клавиатурную навигацию и доступность.
Когда такой подход не подойдёт
- Очень большие объёмы данных в клиенте — фильтрация на клиенте будет медленной.
- Нужна релевантность, ранжирование или синонимы — лучше использовать поисковый движок.
- Конфиденциальные данные, которые нельзя выгружать на клиент — поиск только на сервере.
Мини‑методология разработки
- Определите источник данных: локальный массив или API.
- Решите, где будет фильтрация: клиент или сервер.
- Добавьте контролируемый input с useState.
- Реализуйте фильтрацию и кеширование результатов при необходимости.
- Добавьте debounce, если нужен.
- Протестируйте UX: пустой запрос, нет результатов, быстрое печатание.
Чек‑лист перед выпуском
- Ввод доступен с клавиатуры.
- Фокус и aria-атрибуты для экранных читалок (aria-label, role).
- Debounce для сетевых запросов.
- Показ состояния загрузки при запросе к API.
- Сообщения при пустом результате.
- Тесты: unit для фильтрации, e2e для UX.
Критерии приёмки
- Поиск возвращает ожидаемые элементы при вводе релевантных запросов.
- Интерфейс не блокируется при быстром вводе.
- Для пустого запроса поведение согласовано с требованиями (показывать все/пустое).
- Есть тесты на фильтрацию и на крайние случаи.
Пример решения с debounce (шаблон)
import { useState, useEffect } from 'react'
import debounce from 'lodash/debounce'
export default function Search() {
const [query, setQuery] = useState('')
const [list, setList] = useState([])
const doSearch = (q) => {
// фильтрация или вызов API
const results = posts.filter(p => p.title.toLowerCase().includes(q.toLowerCase()))
setList(results)
}
// debounce на 300 мс
const debouncedSearch = debounce(doSearch, 300)
useEffect(() => {
if (query === '') {
setList([])
return
}
debouncedSearch(query)
return () => debouncedSearch.cancel()
}, [query])
return (
setQuery(e.target.value)} />
{list.map(item => - {item.title}
)}
)
}Решение для больших данных
Если данных много, выполняйте поиск на сервере. Клиент отправляет query и получает уже отфильтрованный и, при необходимости, постранично разбитый набор.
// отправлять запрос на сервер с параметром ?q=...
// сервер возвращает только нужную страницу результатовМентальные модели и эвристики
- «Делай мало на клиенте, если можно сделать много на сервере» — для производительности.
- «Debounce — друг пользователя» — уменьшает количество запросов при быстром вводе.
- «Покажи состояние» — индикаторы загрузки и сообщения при пустом результате улучшают UX.
Диагностическое дерево для выбора подхода
flowchart TD
A[Небольшой набор данных < 1000] -->|Да| B[Фильтрация на клиенте]
A -->|Нет| C[Нужна серверная фильтрация]
C --> D{Требуется ранжирование и полнотекст}
D -->|Да| E[Использовать поисковый движок 'Algolia/Elastic']
D -->|Нет| F[Серверная фильтрация + пагинация]Безопасность и конфиденциальность
- Не отправляйте в аналитике или логах чувствительные запросы пользователей.
- При хранении логов запросов обезличивайте данные.
Краткое резюме
Поисковая строка в React — это управляемый input, фильтрация массива методом filter и отображение через map. Для масштабных задач используйте debounce, серверную фильтрацию или специализированные поисковые сервисы. Тестируйте крайние случаи и обеспечьте доступность интерфейса.
Важно: выбирайте стратегию, исходя из объёма данных и требований к релевантности.
Похожие материалы
Как узнать IP-адрес в Windows 10
Видеозадний фон в Microsoft Edge — включение и отключение
Исправление ошибки 0x800070002c-0x3000d в Windows 10
Cider — клиент Apple Music для Linux
Как использовать FC в командной строке Windows