Как сохранить отзывчивость поля поиска с useDeferredValue в React

Как сохранить отзывчивость поля поиска с useDeferredValue в React
Содержание статьи

Если при каждом нажатии клавиши React заново строит большой список, дайте полю актуальное значение, а списку передайте useDeferredValue(query). В учебном примере на Mentoring.digital эти два значения видно отдельно. Разница позволяет пометить список, пока он показывает результаты предыдущего запроса.

Разделите поле и список

import { memo, useDeferredValue, useState } from "react";

const names = ["Анна", "Антон", "Илья", "Ирина"];

const Results = memo(function Results({ query }) {
  const found = names.filter((name) =>
    name.toLowerCase().includes(query.toLowerCase())
  );
  return <ul>{found.map((name) => <li key={name}>{name}</li>)}</ul>;
});

export default function Search() {
  const [query, setQuery] = useState("");
  const deferred = useDeferredValue(query);
  const isStale = query !== deferred;

  return (
    <>
      <label htmlFor="name-search">Имя</label>
      <input
        id="name-search"
        value={query}
        onChange={(event) => setQuery(event.target.value)}
      />
      <section aria-busy={isStale}>
        {isStale && <p>Обновляем список</p>}
        <Results query={deferred} />
      </section>
    </>
  );
}

На срочном рендере поле получает новый текст. Список может ещё получить прежний deferred. memo помогает пропустить перерисовку списка при прежнем пропсе. Затем React пытается обновить его в фоне и может прервать этот рендер ради нового ввода. Когда результаты догонят поле, отметка об обновлении исчезнет.

Проверьте эффект на реальной нагрузке

Четыре имени нужны для проверки логики. Чтобы заметить разницу, подставьте свой набор с уникальными ключами и измерьте рендер с помощью профилировщика React. Сравните, обновляется ли поле без ожидания списка. Если каждому рендеру списка передаётся новый объект или массив, проверьте стабильность пропсов. Иначе memo будет реже пропускать работу.

Где нужен другой механизм

Для сетевых запросов ограничивайте частоту и отменяйте устаревшие запросы отдельно. У useDeferredValue нет заданного интервала, а перенос рендера на более низкий приоритет сам по себе не сокращает число запросов. Для очень большого списка также проверьте, можно ли рисовать только видимую часть.

Подобрать сценарий профилирования можно на практике по React или разобрать компонент с наставником по React.

Похожие статьи по данной теме