在useEffect钩子中使用两个async await函数是否会引发问题?
问题解答
你写的这段代码本身不会直接触发语法错误,但存在3个需要注意的潜在问题:
- 状态更新异常/警告:如果组件在两个异步请求返回前就卸载,或者
selected的值在请求过程中发生了变化,旧请求返回后仍然会执行setSize、setSize2,轻则触发React「无法对未挂载组件执行状态更新」的警告,重则导致状态和当前selected预期值不匹配的逻辑错误。 - 无效资源浪费:发出的Firestore请求没有取消逻辑,即便已经不需要请求结果(比如
selected已经切换、组件已卸载),请求仍然会走完完整流程,占用带宽和服务端资源。 - 多次重渲染:两个请求独立返回,会分别触发两次状态更新,导致组件连续重渲染两次,如果你需要依赖两个请求的结果做后续操作,现有写法也无法直接判断两个请求是否都已完成。
优化方案
你可以通过useEffect的清理函数加标记位的方式规避上述问题,优化后的参考代码如下:
const [size, setSize] = useState(0) const [size2, setSize2] = useState(0) useEffect(() => { // 标记当前effect是否失效 let isActive = true; const getData1 = async () => { const citiesRef = firestore.collection("users"); const snapshot = await citiesRef .where("item.itemName", "==", selected) .where("selected","==", true) .get(); // 只有当前effect没失效才更新状态 if (isActive) setSize(snapshot.size) }; const getData2 = async () => { const citiesRef = firestore.collection("users"); const snapshot = await citiesRef .where("item.itemName", "==", selected) .where("selected","==", false) .get(); if (isActive) setSize2(snapshot.size) }; if (selected) { getData1(); getData2(); } // 清理函数,effect重新触发/组件卸载时标记为失效 return () => { isActive = false; } }, [selected]);
如果你需要等两个请求都完成后再统一做后续操作,可以用Promise.all包裹两个请求:
useEffect(() => { let isActive = true; const fetchAllData = async () => { const citiesRef = firestore.collection("users"); // 并行发起两个请求 const [snapshot1, snapshot2] = await Promise.all([ citiesRef.where("item.itemName", "==", selected).where("selected","==", true).get(), citiesRef.where("item.itemName", "==", selected).where("selected","==", false).get() ]) if (isActive) { setSize(snapshot1.size) setSize2(snapshot2.size) // 这里可以加两个请求都完成后的后续逻辑 } } if (selected) { fetchAllData() } return () => { isActive = false; } }, [selected])
内容的提问来源于stack exchange,提问作者JS3
相关产品推荐
相关产品推荐

