Typeahead:处理并发请求/竞争条件

问题描述 投票:0回答:1

我已经使用 React 创建了一个预输入。问题是,如果我输入一些内容并输入退格键,则会显示一些以前的结果。

我明白原因是,由于 API 调用是异步的,它会渲染一些先前的调用结果。那么我们如何才能有效地解决这个问题呢?

codeSandbox:https://codesandbox.io/p/sandbox/typeahead-3xrg9y

import React, { useEffect, useState } from "react";
import { fetchSuggestions } from "./API";

export default function Typeahead() {
  const [searchQuery, setSearchQuery] = useState("");
  const [results, setResults] = useState([]);

  useEffect(() => {
    if (!searchQuery) {
      setResults([]);
      return;
    }
    getResults(searchQuery);
  }, [searchQuery]);

  async function getResults(query) {
    const result = await fetchSuggestions(query);
    if (query === searchQuery) {
      setResults(result);
    }
  }

  function inputHandler(e) {
    const query = e.target.value;
    setSearchQuery(query);
  }

  return (
    <div className="container">
      <input onChange={inputHandler} value={searchQuery} />
      <div>
        <ul className="list-container">
          {results.map((res) => (
            <li>{res}</li>
          ))}
        </ul>
        <div />
      </div>
    </div>
  );
}

javascript reactjs deployment frontend
1个回答
0
投票

您只需要为输入添加一些

debounce
,使用每次输入更改时都会重置的
setTimeout
,并且仅在不活动的 300 毫秒(您可以根据需要更改)后调用以获取建议

import React, { useEffect, useState } from "react";
import { fetchSuggestions } from "./API";

export default function Typeahead() {
  const [searchQuery, setSearchQuery] = useState("");
  const [results, setResults] = useState([]);
  const [timerId, setTimerId] = useState(null); // State to keep track of the timeout ID

  useEffect(() => {
    if (!searchQuery) {
      setResults([]);
      return;
    }

    // Clear the existing timeout if there is one
    if (timerId) {
      clearTimeout(timerId);
    }

    const newTimerId = setTimeout(() => {
      getResults(searchQuery);
    }, 300);

    setTimerId(newTimerId);

    // Cleanup function to clear the timeout if the component is unmounted
    return () => clearTimeout(newTimerId);
  }, [searchQuery]);

  async function getResults(query) {
    const result = await fetchSuggestions(query);
    if (query === searchQuery) {
      setResults(result);
    }
  }

  function inputHandler(e) {
    const query = e.target.value;
    setSearchQuery(query);
  }

  return (
    <div className="container">
      <input onChange={inputHandler} value={searchQuery} />
      <div>
        <ul className="list-container">
          {results.map((res) => (
            <li key={res}>{res}</li>
          ))}
        </ul>
        <div />
      </div>
    </div>
  );
}

© www.soinside.com 2019 - 2024. All rights reserved.