React中useEffect调用两个方法仅显示第二个结果的问题求解
状态更新被覆盖的问题解决
问题描述
在useEffect中调用两个数据获取方法时,第二个方法的执行会覆盖第一个的结果,仅能看到第二个方法的输出,第一个的结果短暂显示后消失。
两种写法均出现相同问题:
- 单个
useEffect内调用两个方法:
useEffect(() => { getPages(); getFeatures(); }, []);
此时仅保留getFeatures()的结果,getPages()的结果一秒后消失。
- 两个独立
useEffect分别调用:
useEffect(() => { getFeatures(); console.log("featFeatures"); }, []); useEffect(() => { getPages(); console.log("getPages"); }, []);
能看到两个控制台日志,但仍只保留第二个useEffect的结果,第一个的结果被覆盖。
相关方法代码:getPages():
const getPages = async () => { await getAllPagesFromUser(pageSkip, pageLimit, token).then((data) => { if (data.error) { console.log(data.error); } else { setValues({ ...values, pages: data }); } }); };
getFeatures():
const getFeatures = () => { getAllFeaturesFromUser(featureSkip, featureLimit, token).then((data) => { if (data.error) { console.log(data.error); } else { setValues({ ...values, features: data }); } }); };
原因分析
核心问题是状态更新的闭包陷阱:
两个方法中的values都是组件初始渲染时的快照,当第一个方法完成异步请求并更新状态后,第二个方法执行时依然使用旧的values对象展开,导致第一个方法更新的pages字段被覆盖,最终状态仅保留第二个方法设置的features字段。
解决方案
方案1:使用函数式更新(推荐)
React状态更新函数支持传入回调,回调参数为当前最新状态值,确保每次更新都基于最新状态:
修改getPages():
const getPages = async () => { const data = await getAllPagesFromUser(pageSkip, pageLimit, token); if (data.error) { console.log(data.error); } else { setValues(prevValues => ({ ...prevValues, pages: data })); } };
修改getFeatures():
const getFeatures = async () => { const data = await getAllFeaturesFromUser(featureSkip, featureLimit, token); if (data.error) { console.log(data.error); } else { setValues(prevValues => ({ ...prevValues, features: data })); } };
方案2:合并请求后一次性更新
若两个请求互相独立,可通过Promise.all并行发起请求,待所有请求完成后一次性更新状态,避免多次更新冲突:
useEffect(() => { const fetchData = async () => { try { const [pagesData, featuresData] = await Promise.all([ getAllPagesFromUser(pageSkip, pageLimit, token), getAllFeaturesFromUser(featureSkip, featureLimit, token) ]); const newValues = { ...values }; if (!pagesData.error) newValues.pages = pagesData; if (!featuresData.error) newValues.features = featuresData; setValues(newValues); } catch (err) { console.error('请求出错:', err); } }; fetchData(); }, []);
这种方式仅进行一次状态更新,既避免覆盖问题,又能提升请求效率。
内容的提问来源于stack exchange,提问作者Rohan Srivastava
相关产品推荐
相关产品推荐

