React useEffect钩子为何在页面重载时自动执行?
解决useEffect页面重载时重复执行的问题
问题背景
使用带依赖项数组的useEffect钩子时,每次页面重载都会触发钩子内部代码执行,但已确认依赖项的值并未发生变化,代码如下:
useEffect( function () { console.log('This prints on page load every time'); // 检查用户是否点赞 if (didUserUpvote) { console.log('here'); incrementUserUpvotes(answer.uidCreated); incrementAnswerUpvotes(answer.answerID); appendToArrInDoc('answers', answer.answerID, 'upvotedBy', user.uid); console.log('done'); } }, [didUserUpvote, answer.uidCreated, answer.answerID, user.uid] );
原因分析
页面重载会导致组件重新挂载,而带依赖项数组的useEffect在组件挂载阶段必然会执行一次,这是React的默认设计——无论依赖项是否变化,首次挂载都会触发钩子。如果你的需求是仅在依赖项生命周期内变化时执行(而非挂载时),就需要额外处理。
另外需注意:虽然你看到的依赖项值相同,但如果依赖项是引用类型(如对象、数组),可能存在值看似相同但引用不同的情况(不过你依赖的uidCreated、answerID等一般是字符串/数字这类基本类型,大概率不存在这个问题)。
解决办法
1. 跳过首次挂载执行
添加一个状态标记是否为首次渲染,挂载时直接跳过逻辑执行:
import { useEffect, useState } from 'react'; // 组件内部 const [isFirstRender, setIsFirstRender] = useState(true); useEffect( function () { // 首次渲染时更新标记并返回 if (isFirstRender) { setIsFirstRender(false); return; } console.log('仅在依赖项变化时执行,页面重载不触发'); if (didUserUpvote) { incrementUserUpvotes(answer.uidCreated); incrementAnswerUpvotes(answer.answerID); appendToArrInDoc('answers', answer.answerID, 'upvotedBy', user.uid); } }, [didUserUpvote, answer.uidCreated, answer.answerID, user.uid, isFirstRender] );
2. 仅在didUserUpvote从false变为true时执行
从代码逻辑看,核心是当用户点赞(didUserUpvote为true)时执行操作。如果页面重载时didUserUpvote初始值就是true,会导致重复执行,可通过追踪状态变化来避免:
import { useEffect, useState } from 'react'; // 组件内部 const [prevDidUserUpvote, setPrevDidUserUpvote] = useState(didUserUpvote); useEffect(() => { // 仅当didUserUpvote从false切换为true时执行操作 if (!prevDidUserUpvote && didUserUpvote) { incrementUserUpvotes(answer.uidCreated); incrementAnswerUpvotes(answer.answerID); appendToArrInDoc('answers', answer.answerID, 'upvotedBy', user.uid); } // 更新上一次的状态值 setPrevDidUserUpvote(didUserUpvote); }, [didUserUpvote, answer.uidCreated, answer.answerID, user.uid]);
3. 确认依赖项的稳定性
检查didUserUpvote、answer、user的来源:
- 如果是从props传入,确认父组件是否每次渲染都创建新的对象/数组(比如直接写
answer={{ uidCreated: 'xxx' }}会生成新引用,但你依赖的是对象的基本类型属性,不会影响浅比较结果); - 如果是从状态管理库获取,确认页面重载后的初始状态是否符合预期,是否存在初始化时的隐性变化。
内容的提问来源于stack exchange,提问作者AmongusDev
相关产品推荐
相关产品推荐

