You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 19:12:24