#reactjs #search #next.js #meilisearch
Вопрос:
Поэтому я использую Next.js и построил базовую страницу поиска с вводом и сохранением результатов после запроса в массиве состояний. Проблема в том, что когда я быстро очищаю поле ввода с помощью backspace, оно показывает результат по последнему ключевому слову.
Я считаю, что неправильно использую состояние Реакции.
Вот как я запрашиваю поиск с помощью meilisearch:
const [search, setSearch] = useState([]);
const [showSearch, setShowSearch] = useState(false);
async function onChange(e) {
if (e.length > 0) {
await client.index('sections')
.search(e)
.then((res) => {
const list = res.hits.map((elm) => ({
title: elm.Title,
content: elm.formattedContent
}));
setSearch(list);
setShowSearch(true);
});
} else {
setSearch([]);
setShowSearch(false);
}
}
а вот поле ввода и результаты поиска:
<div className="searchPage wrapper">
<input
type="text"
aria-label="Search through site content"
placeholder="Search your keywords"
onChange={(e) => onChange(e.target.value);}
/>
{showSearch amp;amp; (
<div className="searchPageResults">
<p className="suggested">Top Results</p>
{search.length > 0 ? (
<ul>
{search.map((item, index) => (
<li key={`search-${index}`}>
<Link href={`/${item.slug}`}>
<a role="link">
{item.title}
</a>
</Link>
<p>{item.content}</p>
</li>
))}
</ul>
) : (
<p className="noResults">No results found</p>
)}
</div>
)}
</div>
Каковы наилучшие методы предотвращения подобных ситуаций?
Вы можете проверить живую реализацию здесь: https://budgetbasics.openbudgetsindia.org/search
Чтобы воспроизвести проблему:
- Поищите что-нибудь, например:
Budget
- После отображения результатов удерживайте клавишу backspace, когда поле будет очищено, результаты поиска будут показаны для
b
- Проблемы не возникнет, если я выделю весь текст в поле и удалю его с помощью backspace.
Ответ №1:
Вопрос
Я подозреваю, что, когда вы быстро возвращаетесь назад, последний запрос, выполненный с помощью «b», асинхронно разрешается после выполнения последнего onChange
вызова, где e.length > 0
значение false. search
Состояние обновляется до пустого массива, и как только окончательный асинхронный запрос разрешится search
, состояние обновляется с результатом «b».
Решение
Одним из возможных решений было бы отменить onChange
обработчик, чтобы бесполезные запросы не выполнялись для быстрых наборщиков. списание с lodash-это обычная утилита. Я использовал задержку 300ms
, но это, очевидно, можно настроить в соответствии с вашими потребностями и тем, что лучше всего подходит вам или вашим обычным пользователям.
import debounce from 'lodash/debounce';
async function onChange(e) {
if (e.length > 0) {
await client.index('sections')
.search(e)
.then((res) => {
const list = res.hits.map((elm) => ({
title: elm.Title,
content: elm.formattedContent
}));
setSearch(list);
setShowSearch(true);
});
} else {
setSearch([]);
setShowSearch(false);
}
}
const debouncedOnChange = useMemo(() => debounce(onChange, 300), []);
...
<input
type="text"
aria-label="Search through site content"
placeholder="Search your keywords"
onChange={(e) => debouncedOnChange(e.target.value)} // <-- use debounced handler
/>
Комментарии:
1. кстати, useMemo используется только для оптимизации, верно?
2. @ShoaibAhmed Да. Поскольку это функциональный компонент, вы обычно не хотите повторно объявлять отмененный обратный вызов при каждом рендеринге. Я попробовал это в codesandbox без
useMemo
крючка, и это все еще работало, но я подозреваю, что это было только потому, что ввод является неконтролируемым вводом.