1

因此,我使用 Next.js 并构建了一个带有输入的基本搜索页面,并将查询后的结果存储在状态数组中。问题是当我使用退格快速清除输入字段时,它会显示最后一个关键字的结果。

我相信我以错误的方式使用 React 状态。

这是我使用 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 && (
          <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
  • 显示结果后,按住退格键,当字段被清除时,搜索结果显示为b
  • 如果我选择字段中的所有文本并使用退格键将其删除,则问题不存在。
4

1 回答 1

2

问题

我怀疑当你快速退格时,最后一次调用“b”发出的最后一个请求会在最后一次调用异步解析,where是 false。状态被更新为一个空数组,一旦最终异步请求解决,状态就会更新为“b”的结果。onChangee.length > 0searchsearch

解决方案

一种可能的解决方案是消除onChange处理程序的抖动,因此不会为快速打字机发出无用的请求。debounce from 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
/>
于 2021-08-13T07:10:54.937 回答