如何处理反应前端中以错误顺序到达的服务器响应?

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

我的 React 前端中有一个搜索输入字段,用户可以在其中输入内容,每当值发生变化时,就会将发布请求发送到与弹性搜索通信的 Web 服务器。问题如下:

  • 用户开始输入:“h”=> 搜索请求已发送,并且需要很长时间,因为许多条目包含“h”。
  • 用户完成输入:“hello”=> 再次发送搜索请求,但时间要短得多

结果:React 首先获取“hello”的响应,然后获取“h”的响应。因此 h 的结果会覆盖“hello”的结果,这不是我想要的。

我该如何解决这个问题?

编辑:

  useEffect(() => {
    doSearch();
  }, [query, cbTitle, cbAbstract, cbAuthor, cbInstitution]); // trickered when input (aka query or cb=Checkboxes) changes 

doSearch(){
...
    axios
      // .post(`http://XXX:5000/search`, data, axios_config)
      .post(`/search`, data, axios_config)
      .then((res) => {
        // console.log(res);
        // console.log(res.data);
        setSearchResponse(res.data);
      });
  };
}

编辑2:答案中提到的方法

    axios
      .post(`http://XXX:5000/search`, data, axios_config)
      // .post(`/search`, data, axios_config)
      .then((res) => {
        // console.log(res);
        // console.log(res.data);
        if (
          res.data["query"] === query &&
          res.data["location"] === searchLocation
        ) {
          console.log("latest state:");
          console.log(query);
          setSearchResponse(res.data["result"]);
        }
      });
  };

编辑3:整个组件

import React, { useState, useEffect } from "react";
import Card from "./CardPaper";
import axios from "axios";

let axios_config = {
  headers: {
    data: { location: "aits" },
    dataType: "json",
    xhrFields: {
      withCredentials: true,
    },
    crossDomain: true,
    contentType: "application/json; charset=utf-8",
  },
};

function Search() {
  const [query, setQuery] = useState("");
  const [cbTitle, setcbTitle] = useState(true);
  const [cbAbstract, setcbAbstract] = useState(true);
  const [cbAuthor, setcbAuthor] = useState(true);
  const [cbInstitution, setcbInstitution] = useState(true);
  const [searchLocation, setSearchLocation] = useState("");
  const [searchResponse, setSearchResponse] = useState([]);

  useEffect(() => {
    doSearch();
  }, [query, cbTitle, cbAbstract, cbAuthor, cbInstitution]);

  const doSearch = () => {
    let search_location = "";
    if (cbTitle === true) {
      search_location += "t";
    }
    if (cbAuthor === true) {
      search_location += "a";
    }
    if (cbAbstract === true) {
      search_location += "s";
    }
    if (cbInstitution === true) {
      search_location += "i";
    }
    setSearchLocation(search_location);
    let data = { query: query, location: search_location };
    axios
      .post(`http://XXX:5000/search`, data, axios_config)
      // .post(`/search`, data, axios_config)
      .then((res) => {
        if (
          res.data["query"] === query &&
          res.data["location"] === searchLocation
        ) {
          console.log("latest state:");
          console.log(query);
          setSearchResponse(res.data["result"]);
        }
      });
  };

  return (
    <div className="container mx-auto">
      <input
        className="block mx-auto w-1/2 border-2 border-gray-300 bg-white h-10 px-5 pr-16 rounded-lg mt-8 focus:outline-none"
        type="search"
        name="search"
        placeholder="Search for title, author or phrases in the abstract of a paper"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      <div className="mx-auto w-1/2">
        <div>
          <span className="pl-2">found {searchResponse.length} results</span>
        </div>
        <div>
          <label className="ml-3 block md:inline">
            <input
              type="checkbox"
              class="text-gray-600"
              defaultChecked={cbTitle}
              onChange={() => {
                setcbTitle(!cbTitle);
              }}
            />
            <span className="ml-2 text-gray-700">Title</span>
          </label>
          <label className="ml-3 block md:inline">
            <input
              type="checkbox"
              class="ext-gray-600"
              checked={cbAbstract}
              onChange={() => {
                setcbAbstract(!cbAbstract);
              }}
            />
            <span className="ml-2 text-gray-700">Abstract</span>
          </label>
          <label className="ml-3 block md:inline">
            <input
              type="checkbox"
              class="text-gray-600"
              checked={cbAuthor}
              onChange={() => {
                setcbAuthor(!cbAuthor);
              }}
            />
            <span className="ml-2 text-gray-700">Author</span>
          </label>
          <label className="ml-3 block md:inline">
            <input
              type="checkbox"
              class="ext-gray-600"
              checked={cbInstitution}
              onChange={() => {
                setcbInstitution(!cbInstitution);
              }}
            />
            <span className="ml-2 text-gray-700">Institution</span>
          </label>
        </div>
      </div>
      {searchResponse.map(function (item, index) {
        return (
          <Card
            title={item["title"]}
            abstract={item["abstract"]}
            authors={item["authors"]}
            affliatedInstitutions={item["institutions"]}
            link={item["url"]}
          />
        );
      })}
    </div>
  );
}

export default Search;
reactjs elasticsearch
4个回答
1
投票

一种选择是将最新搜索到的文本存储在客户端,并在更新 DOM 之前将其与响应进行检查。

示例:下面的函数将为您提供一个想法,我将用户输入存储在变量(latestInput)中,并在响应中我带来相同的数据并进行比较。如果两者匹配则进行更新。

function postSearchData()
{
   axios
  .post(`/search`, data, axios_config)
  .then((res) => {
    if(res.data.searchText === query)
       setSearchResponse(res.data);
  });
}

1
投票
useEffect(() => {
let ignore = false;
async function fetchProduct() {
  const response = await fetch('http://myapi/product/' + productId);
  const json = await response.json();
  if (!ignore) setProduct(json);
}

fetchProduct();
return () => { ignore = true };

}, [产品ID]);

上述方法将解决乱序请求问题。在本地测试过,效果很好。


0
投票

可以在setSearchResponse中添加索引


0
投票

试试这个:

useEffect(() => {
    ignoreRef = [false]
    doSearch()
    return () => { ignoreRef[0] = true }
  }, [...])

  const doSearch = (ignoreRef = [false]) => {
    ...
    axios.post(...)
      .then((res) => {
        if (ignoreRef[0]) return
        // Do whatever you want and change states
      })
  }
© www.soinside.com 2019 - 2024. All rights reserved.