React/Next中useEffect重复调用及teamData刷新后重置为null的解决方法
问题解决:阻止teamData重置为null + 减少useEffect不必要调用
问题根源
你遇到的问题本质是两个点:
- Next.js中
router.query.id在页面刷新时会经历「从undefined到实际值」的过程,导致依赖id的useEffect多次触发; - 无效
id(比如undefined)发起的API请求,若响应晚于有效id的请求,会用错误数据(比如null)覆盖已加载的正确teamData——也就是竞态问题。
解决方案
以下是针对性的代码修复,同时解决两个问题:
const router = useRouter(); const { id } = router.query; const [teamData, setTeamData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // 1. 过滤无效id,避免发起无意义的API请求 if (!id) { setLoading(false); return; } // 2. 标记当前请求是否有效,防止旧请求覆盖新数据 let isCurrentRequest = true; // 发起请求前重置loading状态 setLoading(true); GetTeamData(id) .then((value) => { // 仅当当前请求未被取消时,才更新状态 if (isCurrentRequest) { setTeamData(value); setLoading(false); console.log("Got Value"); } }) .catch((error) => { if (isCurrentRequest) { setLoading(false); console.error("获取团队数据失败:", error); } }); // 组件卸载或id变化时,标记旧请求无效 return () => { isCurrentRequest = false; }; }, [id]);
关键优化点解释
- 过滤无效id:只有当
id存在时才发起API请求,直接避免了id为undefined时的无效调用,减少useEffect触发次数; - 处理竞态问题:用
isCurrentRequest变量标记请求有效性,当组件卸载或id变化时,旧请求的响应会被忽略,不会覆盖新的正确数据; - 合理控制loading:仅在发起有效请求时设置
loading为true,避免页面初始加载时不必要的loading状态。
关于「让useEffect仅调用一次」的说明
如果业务场景确实需要useEffect只执行一次(比如路由参数不会变化),可以将依赖项改为空数组[],但要确保id在组件挂载时已经存在。不过这种方式不推荐用于路由参数可能变化的场景,会导致数据无法随id更新。更稳妥的方式是上面的方案,既保证必要时触发请求,又避免无效调用和数据覆盖问题。
内容的提问来源于stack exchange,提问作者AR0106
相关产品推荐
相关产品推荐

