首页 > 解决方案 > 如何在 AJAX 调用中查询应用程序状态?

问题描述

我正在尝试制作一个自动完成的反应组件。目前我正在使用 Github 的用户搜索 API 来查询与给定查询字符串匹配的用户。自动完成大部分时间都可以正常工作。但是,因为我同时进行多个 AJAX 调用,有时查询 1的响应处理程序会在查询 2 的响应处理程序之后触发。例如:

  1. 用户输入查询字符串“alex”
  2. JS 为字符串“a”、“al”、“ale”和“alex”触发 4 个异步 AJAX 查询。
  3. 查询“a”的响应处理程序返回。
  4. 查询“al”返回的响应处理程序。
  5. 查询“alex”的响应处理程序返回。
  6. 查询“ale”的响应处理程序返回。
  7. 用户按预期看到查询“ale”而不是“alex”的结果。

这里有一些代码来证明这一点:https ://codepen.io/alexspurling/pen/gOOWNpa?editors=0010

(请注意,如果您运行此代码,则每分钟有 10 个请求的速率限制。如果它停止工作,请稍等一下,然后重试)

结果

安慰

正如您从控制台输出中看到的,结果以错误的顺序返回,并且此处显示的结果是针对查询“a”,而不是“alex”。

我尝试的解决方案是跟踪我的应用程序状态中最近提交的查询(请参阅lastQuery变量)。然而,这失败了,因为当receivedResults函数被调用时,我只能访问旧的“封闭”值,而不是这部分应用程序状态的实际当前值。

我的问题是,是否可以从异步响应处理程序中读取实际的当前状态?如果不是,是因为它会破坏单向数据流吗?您将如何以保持单向数据流的方式实现所需的行为?

注意:我不想使用去抖动或延迟。我也不想在飞行请求中中止。我的问题更笼统地涉及 React 应用程序中的数据流。自动完成示例只是演示问题的好方法。

标签: javascriptreactjs

解决方案


解决问题的一种可能方法是使用 React refs,这是修改后的 codepen:https ://codepen.io/rikin/pen/RwwVXeM?editors=0011

我修改了您的Auto组件,如下所示:

function Auto(props) {
  const inputref = React.useRef(null); // <-------------------------
  const [value, setValue] = React.useState('');

  React.useEffect(() => {
    const queryNum = props.lastQuery + 1;
    search(value, queryNum, inputref); // <-------------------------
    props.setLastQuery(queryNum);   }, [value, inputref]);

  async function search(value, queryNum, inputref) {
    const url = 'https://api.github.com/search/users?q=' + value;
    const resp = await fetch(url)
    const json = await resp.json()
    if (json.items) {
      const users = json.items.map((item) => {
        return item.login;
      });
      inputref.current.value === value // <-----------------------
        && props.setResults({query: value, queryNum: queryNum, users: users});
    }   }

  return (
    <input value={value} ref={inputref} onChange={(e) => {setValue(e.target.value)}}></input>
                         ^^^^^^^^^^^^^^   
  ) }

通过这样做,您不会取消飞行中的请求,也不会使用去抖动或延迟。相反,一旦响应返回,您正在检查输入的电流value,如果它与在valueAPI 请求期间传递给它的匹配,那么它将执行set操作,否则它将丢弃。

可能还有其他方法(甚至更多性能或正确的方法),这是我尝试解决问题的一种可能方法。


推荐阅读