我有这个useEffect
应该只运行一次。因此,我将router.query.something
设置为依赖项。请求必须等待router.query.something
被水化,然后只有当值为真时才发出请求。
这似乎是一个过于复杂的函数,向API发出一个简单的一次性请求,但我还没有找到一个更清晰的方法来实现它。
const MyPage = () => {
const [user, setUser] = useState(null)
const router = useRouter()
useEffect(async () => {
try {
if (router.query.something) {
const res = await api.get(`/resetTokens/${router.query.something}`)
setUser(res.data)
}
} catch (err) {
setUser(null)
}
}, [router.query.something])
return (<div>...</div>)
}
通常情况下,我会使用getServerSideProps
,但在这种情况下,我不能,因为请求正在设置cookie。如果我使用getServerSideProps
, cookie不会传递到客户端。
您应该注意两件事:
首先,useEffect
不应该使用async
函数。在控制台中应该有一个关于在useEffect
中使用async
的警告。
其次,您应该清理useEffect
,因为您正在处理承诺。如果不进行清理,可能会遇到内存泄漏,从而导致意想不到的结果。
你的代码应该是这样的
useEffect(() => {
let isMounted = true;
if (router.query.something) {
api.get(`/resetTokens/${router.query.resetToken}`)
.then(res=> {
if(!isMounted) return;
setUser(res.data)
})
.catch(e => {
if(!isMounted) return;
setUser(null)
});
}
return () => {
isMounted = false;
};
}, [router.query.something])
您也可以尝试使用AbortController
执行此操作。学术界有一个很好的博客,解释了正在发生的事情以及如何解决。https://academind.com/tutorials/useeffect-abort-http-requests/
const MyPage = () => {
const [user, setUser] = useState(null)
const router = useRouter()
useEffect(() => {
const abortController = new AbortController();
const fetchData = async () => {
try {
const res = fetch(`/resetTokens/${router.query.resetToken}`, { signal: abortController.signal });
setUser(res.data)
} catch (e) {
setUser(null)
}
};
if (router.query.something) {
fetchData();
}
return () => {
abortController.abort();
};
}, [router.query.something]);
return (<div>...</div>)
}