javascript - 如何在 AJAX 调用中查询应用程序状态?
问题描述
我正在尝试制作一个自动完成的反应组件。目前我正在使用 Github 的用户搜索 API 来查询与给定查询字符串匹配的用户。自动完成大部分时间都可以正常工作。但是,因为我同时进行多个 AJAX 调用,有时查询 1的响应处理程序会在查询 2 的响应处理程序之后触发。例如:
- 用户输入查询字符串“alex”
- JS 为字符串“a”、“al”、“ale”和“alex”触发 4 个异步 AJAX 查询。
- 查询“a”的响应处理程序返回。
- 查询“al”返回的响应处理程序。
- 查询“alex”的响应处理程序返回。
- 查询“ale”的响应处理程序返回。
- 用户按预期看到查询“ale”而不是“alex”的结果。
这里有一些代码来证明这一点:https ://codepen.io/alexspurling/pen/gOOWNpa?editors=0010
(请注意,如果您运行此代码,则每分钟有 10 个请求的速率限制。如果它停止工作,请稍等一下,然后重试)
正如您从控制台输出中看到的,结果以错误的顺序返回,并且此处显示的结果是针对查询“a”,而不是“alex”。
我尝试的解决方案是跟踪我的应用程序状态中最近提交的查询(请参阅lastQuery
变量)。然而,这失败了,因为当receivedResults
函数被调用时,我只能访问旧的“封闭”值,而不是这部分应用程序状态的实际当前值。
我的问题是,是否可以从异步响应处理程序中读取实际的当前状态?如果不是,是因为它会破坏单向数据流吗?您将如何以保持单向数据流的方式实现所需的行为?
注意:我不想使用去抖动或延迟。我也不想在飞行请求中中止。我的问题更笼统地涉及 React 应用程序中的数据流。自动完成示例只是演示问题的好方法。
解决方案
解决问题的一种可能方法是使用 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
,如果它与在value
API 请求期间传递给它的匹配,那么它将执行set
操作,否则它将丢弃。
可能还有其他方法(甚至更多性能或正确的方法),这是我尝试解决问题的一种可能方法。