超时函数中未清除异步代码
我在我的 React 应用程序中遇到了有关 setTimeout 函数中的异步调用的错误。基本上,当我想清除超时时,我有一个条件,但由于某种原因,其中的代码在清除后仍然执行(我确信满足条件)。我有下面应用程序的 codeandbox 链接。问题是,当我输入一些内容并得到结果时,然后单击“加载更多”按钮,然后在完成加载之前,我在输入中再添加一个字母,它说它正在搜索最新的输入,但实际上我得到了前一个输入的 2 个结果输入,几秒钟后我得到与最新输入匹配的结果。在 useEffect 内部,我检查它是否正在加载,如果是,我清除超时,但它显然不起作用。有办法解决这个问题吗?
import { useState, useEffect, useRef } from "react";
import axios from "axios";
import Loading from "./Loading";
import SearchResult from "./SearchResult";
export default function App() {
const [users, setUsers] = useState([]);
const [filter, setFilter] = useState("");
const [loading, setLoading] = useState(false);
const page = useRef(2);
let timeout1 = useRef(null);
const fetchData = async (filter, page = 1) => {
if (filter === "") return;
try {
console.log(filter);
const perPage = 1;
const res = await axios.get(
`https://api.github.com/search/users?q=${filter}+in%3Alogin&page=${page}&per_page=${perPage}`
);
setLoading(false);
return res.data.items;
} catch (e) {
console.log(e);
}
};
useEffect(() => {
if (loading) {
clearTimeout(timeout1.current);
console.log(timeout1.current);
console.log("aborted");
}
const timeOut = setTimeout(async () => {
if (filter) {
const users = await fetchData(filter);
console.log(users);
setUsers(users);
}
}, 4800);
return () => {
clearTimeout(timeOut);
console.log(loading);
};
}, [filter]);
const handleFilter = (e) => {
setTimeout(() => {
setFilter(e.target.value);
setLoading(true);
setUsers([]);
}, 2000);
};
const handleLoad = () => {
setLoading(true);
timeout1.current = setTimeout(async () => {
const res = await fetchData(filter, page.current);
console.log(res);
setUsers([...users, ...res]);
page.current += 1;
}, 6000);
};
return (
<div className="parent">
<input onChange={(e) => handleFilter(e)} />
<div className="people">
{users ? (
users.map(({ login, avatar_url, html_url }) => {
return (
<SearchResult
key={login}
name={login}
url={avatar_url}
githubUrl={html_url}
/>
);
})
) : (
<div></div>
)}
{users.length > 0 && loading === false ? (
<button onClick={handleLoad}>load more</button>
) : (
<></>
)}
{loading ? <Loading filter={filter} /> : <></>}
</div>
</div>
);
}
I've encountered and error in my react application regarding async calls in setTimeout function. Basically I have a condition when I want to clear the timeout but for some reason the code inside it still executes after it is cleared(I'm positive the condition is met). I have a codesandbox link of the app below. The thing is, when I input something and get a result, then click load more button, then before it finishes loading I add one more letter to the input, it says it's searching for the latest input but I actually get 2 results of the previous input and after a few seconds I get the result matching the latest input. Inside useEffect I check if it is loading, if it is I clear the timeout but it clearly does not work. Is there a way to solve this problem?
import { useState, useEffect, useRef } from "react";
import axios from "axios";
import Loading from "./Loading";
import SearchResult from "./SearchResult";
export default function App() {
const [users, setUsers] = useState([]);
const [filter, setFilter] = useState("");
const [loading, setLoading] = useState(false);
const page = useRef(2);
let timeout1 = useRef(null);
const fetchData = async (filter, page = 1) => {
if (filter === "") return;
try {
console.log(filter);
const perPage = 1;
const res = await axios.get(
`https://api.github.com/search/users?q=${filter}+in%3Alogin&page=${page}&per_page=${perPage}`
);
setLoading(false);
return res.data.items;
} catch (e) {
console.log(e);
}
};
useEffect(() => {
if (loading) {
clearTimeout(timeout1.current);
console.log(timeout1.current);
console.log("aborted");
}
const timeOut = setTimeout(async () => {
if (filter) {
const users = await fetchData(filter);
console.log(users);
setUsers(users);
}
}, 4800);
return () => {
clearTimeout(timeOut);
console.log(loading);
};
}, [filter]);
const handleFilter = (e) => {
setTimeout(() => {
setFilter(e.target.value);
setLoading(true);
setUsers([]);
}, 2000);
};
const handleLoad = () => {
setLoading(true);
timeout1.current = setTimeout(async () => {
const res = await fetchData(filter, page.current);
console.log(res);
setUsers([...users, ...res]);
page.current += 1;
}, 6000);
};
return (
<div className="parent">
<input onChange={(e) => handleFilter(e)} />
<div className="people">
{users ? (
users.map(({ login, avatar_url, html_url }) => {
return (
<SearchResult
key={login}
name={login}
url={avatar_url}
githubUrl={html_url}
/>
);
})
) : (
<div></div>
)}
{users.length > 0 && loading === false ? (
<button onClick={handleLoad}>load more</button>
) : (
<></>
)}
{loading ? <Loading filter={filter} /> : <></>}
</div>
</div>
);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我在处理引用时忘记使用 .current ,因此它不起作用。
I forgot to use .current when working with references and it wasn't working because of that.