0

0

解决 React 中 useEffect 运行两次的问题

霞舞

霞舞

发布时间:2025-10-10 09:53:30

|

615人浏览过

|

来源于php中文网

原创

解决 react 中 useeffect 运行两次的问题

摘要:本文旨在帮助开发者理解并解决 React 应用中 useEffect 钩子意外运行两次的问题。我们将深入探讨导致此现象的常见原因,并提供相应的解决方案,确保你的副作用函数仅在预期时机执行,避免潜在的性能问题和数据不一致。通过本文的学习,你将能够更好地控制 useEffect 的行为,构建更稳定、更高效的 React 应用。

在 React 开发中,useEffect 是一个强大的钩子,用于处理副作用操作,如数据获取、订阅事件等。然而,有时开发者会遇到 useEffect 运行两次的意外情况,这可能会导致不必要的 API 调用、资源浪费,甚至数据错误。本文将深入探讨导致 useEffect 运行两次的常见原因,并提供相应的解决方案。

常见原因及解决方案

  1. React Strict Mode

    React 的 Strict Mode 是一种开发模式,旨在帮助开发者发现潜在的问题。在 Strict Mode 下,React 会故意调用某些函数两次,包括 useEffect 中的副作用函数。这有助于开发者识别那些不纯的副作用函数,即那些会修改组件外部状态的函数。

    解决方案:

    • 开发环境 如果你只在开发环境中遇到此问题,并且确认你的副作用函数是纯的,可以暂时禁用 Strict Mode 来避免重复执行。但请注意,这会隐藏潜在的问题,因此建议在发布前重新启用 Strict Mode 进行检查。
    • 生产环境: 在生产环境中,不应禁用 Strict Mode。如果 useEffect 运行两次导致问题,你需要修改副作用函数,使其成为纯函数。例如,确保在副作用函数中只进行数据获取或更新组件内部状态,避免直接修改全局变量或外部 API。

    示例:

    假设你的 index.tsx 文件中使用了 Strict Mode:

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import App from './App';
    
    const root = ReactDOM.createRoot(
      document.getElementById('root') as HTMLElement
    );
    root.render(
      
        
      
    );

    你可以暂时移除 来禁用 Strict Mode。

  2. 依赖项问题

    useEffect 的第二个参数是一个依赖项数组,用于指定 effect 应该在哪些值发生变化时重新运行。如果依赖项数组为空 [],则 effect 只会在组件首次渲染时运行一次。但是,如果依赖项数组中的值发生变化,effect 就会重新运行。

    解决方案:

    • 检查依赖项: 仔细检查依赖项数组,确保其中只包含 effect 真正依赖的值。如果依赖项数组包含不必要的值,effect 可能会在不应该运行的时候运行。
    • 使用正确的依赖项: 确保依赖项数组中的值是最新的。如果依赖项数组中的值是过时的,effect 可能会在应该运行的时候没有运行。

    示例:

    import React, { useState, useEffect } from 'react';
    
    function MyComponent() {
      const [count, setCount] = useState(0);
      const [name, setName] = useState('Initial Name');
    
      useEffect(() => {
        console.log('Effect is running');
        document.title = `Count: ${count}`;
      }, [count]); // Only runs when 'count' changes
    
      return (
        

    Count: {count}

    setName(e.target.value)} />
    ); } export default MyComponent;

    在这个例子中,useEffect 只会在 count 的值发生变化时运行,因为 count 是唯一的依赖项。如果添加了 name 作为依赖项,那么每次 name 改变时,useEffect 也会运行。

    行业贸易网站管理系统 2007 Beta 1
    行业贸易网站管理系统 2007 Beta 1

    1.修正BUG站用资源问题,优化程序2.增加关键词搜索3.修改报价4.修正BUG 水印问题5.修改上传方式6.彻底整合论坛,实现一站通7.彻底解决群发垃圾信息问题。注册会员等发垃圾邮件7.彻底解决数据库安全9.修改交易方式.增加网站担保,和直接交易两中10.全站可选生成html.和单独新闻生成html(需要装组建)11. 网站有10中颜色选择适合不同的行业不同的颜色12.修改竞价格排名方式13.修

    下载
  3. 组件重新渲染

    如果组件由于其他原因重新渲染,useEffect 也会重新运行。这可能是由于父组件的状态更新、props 改变,或者使用了 forceUpdate 等方法。

    解决方案:

    • 优化组件渲染 使用 React.memo、useMemo、useCallback 等方法来优化组件的渲染性能,避免不必要的重新渲染。
    • 避免不必要的状态更新: 仔细检查你的代码,确保只在必要时更新组件的状态。

    示例:

    import React, { useState, useEffect, memo } from 'react';
    
    const MyChildComponent = memo(({ data }) => {
      useEffect(() => {
        console.log('Child Effect running with data:', data);
      }, [data]);
    
      return 

    Data from parent: {data}

    ; }); function MyParentComponent() { const [parentCount, setParentCount] = useState(0); return (
    ); } export default MyParentComponent;

    在这个例子中,MyChildComponent 使用 memo 进行包裹,只有当 data prop 发生变化时才会重新渲染,从而避免了不必要的 useEffect 运行。

  4. Next.js 开发环境下的 Fast Refresh

    在使用 Next.js 开发时,Fast Refresh 功能可能会导致 useEffect 在保存代码时运行两次。这是为了提供更快的开发体验,但有时会导致副作用函数意外执行。

    解决方案:

    • 检查代码逻辑: 确保你的副作用函数是幂等的,即多次执行不会产生副作用。
    • 条件执行: 可以添加条件判断,只在特定情况下执行副作用函数。

    示例(基于问题中的代码):

    问题中的代码存在 loading 状态管理的问题,导致 useEffect 运行两次,并且 loading 状态始终为 false。以下是修改后的代码:

    import { type AppType } from 'next/app';
    import { api } from '~/utils/api';
    import '~/styles/globals.css';
    import Nav from '~/components/Nav';
    import { useEffect, useState } from 'react';
    
    const MyApp: AppType = ({ Component, pageProps }) => {
      const [showCart, setShowCart] = useState(false);
      const [loading, setLoading] = useState(true); // Set initial loading state to true
    
      const createSession = api.user.createSession.useMutation();
    
      const generateId = async (): Promise => {
        const res = await createSession.mutateAsync();
        if (res.response) {
          return res.response.id;
        } else if (res.error) {
          return res.error;
        }
      };
    
      const setSessionId = async () => {
        const tmp: string | undefined = await generateId();
        if (tmp) document.cookie = `sessionId=${tmp}`;
        setLoading(false);
      };
    
      useEffect(() => {
        const getSessionId = () => {
          const cookieString: string = document.cookie;
          const cookies: string[] = cookieString.split(';') || [];
    
          let sessionId: string | null = null;
    
          for (let i = 0; i < cookies.length; i++) {
            const cookie: string | undefined = cookies[i];
    
            if (!cookie || cookie.trim() === '') {
              continue;
            }
    
            if (cookie.trim().startsWith('sessionId=')) {
              sessionId = cookie.trim().substring('sessionId='.length);
              break;
            }
          }
    
          return sessionId;
        };
    
        if (!getSessionId()) {
          setSessionId();
        } else {
          setLoading(false); // Set loading to false if session ID is present
        }
      }, []);
    
      return (
        <>
          

    关键修改:

    • 初始 loading 状态: 将 loading 的初始状态设置为 true,确保在获取 session ID 之前显示 "LOADING"。
    • getSessionId 函数: 提取获取 session ID 的逻辑到单独的函数中,提高代码可读性
    • 在找到 session ID 后设置 loading 为 false: 如果在 cookie 中找到了 session ID,则将 loading 设置为 false。

总结

useEffect 运行两次通常是由于 React Strict Mode、依赖项问题、组件重新渲染或 Next.js Fast Refresh 引起的。通过理解这些原因,并采取相应的解决方案,你可以更好地控制 useEffect 的行为,构建更稳定、更高效的 React 应用。在调试 useEffect 时,始终要仔细检查依赖项、组件渲染逻辑,并考虑是否启用了 Strict Mode 或 Fast Refresh。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.11.20

cookie
cookie

Cookie 是一种在用户计算机上存储小型文本文件的技术,用于在用户与网站进行交互时收集和存储有关用户的信息。当用户访问一个网站时,网站会将一个包含特定信息的 Cookie 文件发送到用户的浏览器,浏览器会将该 Cookie 存储在用户的计算机上。之后,当用户再次访问该网站时,浏览器会向服务器发送 Cookie,服务器可以根据 Cookie 中的信息来识别用户、跟踪用户行为等。

6427

2023.06.30

document.cookie获取不到怎么解决
document.cookie获取不到怎么解决

document.cookie获取不到的解决办法:1、浏览器的隐私设置;2、Same-origin policy;3、HTTPOnly Cookie;4、JavaScript代码错误;5、Cookie不存在或过期等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

347

2023.11.23

阻止所有cookie什么意思
阻止所有cookie什么意思

阻止所有cookie意味着在浏览器中禁止接受和存储网站发送的cookie。阻止所有cookie可能会影响许多网站的使用体验,因为许多网站使用cookie来提供个性化服务、存储用户信息或跟踪用户行为。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

411

2024.02.23

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

91

2025.08.19

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

315

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

748

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

91

2025.08.19

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

CSS教程
CSS教程

共754课时 | 24.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号