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

组件挂载时useEffect调用两次,已用useCallback仍未解决

解决方案:在React StrictMode下避免重复执行API调用

在React开发环境的StrictMode中,React会刻意重复调用useEffect、组件挂载逻辑等,以此帮助检测潜在bug。要在保留StrictMode的前提下让API调用只执行一次,可通过以下几种方式实现:

方法1:使用Ref标记执行状态

利用useRef存储执行状态标记,Ref的引用在组件生命周期内稳定且更新不会触发重渲染:

import { useCallback, useEffect, useRef } from 'react';

function YourComponent() {
  const isCalled = useRef(false);

  const sendCode = useCallback(() => {
    console.log('InsideSendCode');
    // 替换为你的API调用逻辑
  }, []);

  useEffect(() => {
    if (!isCalled.current) {
      sendCode();
      isCalled.current = true;
    }
  }, [sendCode]);

  return <div>Your Component</div>;
}

原理:第一次触发useEffect时标记为未执行,调用sendCode后更新标记;第二次StrictMode触发useEffect时,因标记已为true直接跳过执行。

方法2:简化逻辑(无需复用sendCode时)

如果sendCode仅用于本次挂载逻辑,可直接将逻辑放入useEffect并配合Ref控制:

import { useEffect, useRef } from 'react';

function YourComponent() {
  const isCalled = useRef(false);

  useEffect(() => {
    if (!isCalled.current) {
      console.log('InsideSendCode');
      // 你的API调用逻辑
      isCalled.current = true;
    }
  }, []);

  return <div>Your Component</div>;
}

方法3:封装自定义Hook(多组件复用场景)

如果多个组件需要类似“仅挂载执行一次”的逻辑,可封装成自定义Hook:

import { useEffect, useRef } from 'react';

function useMountOnce(callback) {
  const isExecuted = useRef(false);

  useEffect(() => {
    if (!isExecuted.current) {
      callback();
      isExecuted.current = true;
    }
  }, [callback]);
}

// 使用示例
function YourComponent() {
  const sendCode = useCallback(() => {
    console.log('InsideSendCode');
    // API调用逻辑
  }, []);

  useMountOnce(sendCode);

  return <div>Your Component</div>;
}

注意事项

  • 该方案仅针对开发环境StrictMode的重复执行问题,生产环境中React不会触发此类重复调用,无额外性能开销。
  • 不要用useState标记执行状态,setState会触发组件重渲染,可能导致不必要的渲染循环。

内容的提问来源于stack exchange,提问作者Daniciuc Razvan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:42:25