[译] 为何 React 18 中 useEffect 会运行两次?

React18发布后,useEffect在开发模式下默认可能会运行两次,仅限于strict mode。这可能导致应用行为变化,但只影响开发环境。为解决此问题,可以暂时禁用strict mode,如在Next.js中设置reactStrictMode: false,或者在create-react-app应用中移除StrictMode组件。这是一个临时解决方案,开发者应修复任何由此产生的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

f634db20a738aed9a9e1ba007f1c74b2.png

原文:https://flaviocopes.com/react-useeffect-two-times/

在 2022 年 3 月发布的 React 18 的发布公告中,数量可观的新特性扑面而来。而对 useEffect() 的默认行为的改变,可能就此被淹没了。

如果你的应用在更新到 React 18 之后行为迥异,或许正是因为 useEffect() 默认变为被运行 2 次了

虽然这种情况只发生在 development mode 中,但无疑每位开发者都会遇到。

另一个限制条件是 只在 strict mode 发生,但这同样是用 create-react-app 或 Next.js 所构建应用的默认选项。

事情就是这么个事情,所以不用紧张是不是代码出了什么问题 -- React 的现状如此。

唯一避免这种行为的方法就是 禁用 strict mode;鉴于严格模式的重要性,这毕竟是个你能修复这种改变引入的任何问题之前临时的变通之策。

在 Next.js 中,可以在 next.config.js 文件里增加这个选项:

reactStrictMode: false

create-react-app 创建的应用里,可以把 index.js 文件里的 StrictMode 高阶组件去除:

比如从这样:

import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

import App from './App';

const rootElement = document.getElementById('root');
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

改为:

import React from 'react';
import { createRoot } from 'react-dom/client';

import App from './App';

const rootElement = document.getElementById('root');
const root = createRoot(rootElement);

root.render(
  <App />
);

d2243f2bfca57b7ece2e5dd974eaf6f2.png6807f708cc0516339c084299f08261de.png

React中,useEffect是一个用于处理副作用操作的Hook函数。副作用操作指的是在组件渲染过程中执行的与组件状态无关的操作,例如发送网络请求、订阅事件、操作DOM等。通过使用useEffect,我们可以在函数组件中模拟类组件的生命周期方法,如componentDidMount和componentWillUnmount。 基本用法是通过导入React模块中的useEffect函数,并在函数组件中调用它。useEffect接受两个参数,第一个参数是一个函数,用于指定副作用操作的逻辑。第二个参数是一个依赖数组,用于指定在哪些依赖项发生变化时重新运行副作用操作。 如果第二个参数为空数组[],则表示副作用操作只运行一次,相当于componentDidMount。这时,副作用操作将在组件挂载和卸载时执行。例如: ``` import { useEffect } from "react"; useEffect(() => { console.log('页面渲染完成'); }, []); ``` 如果返回函数,该函数将在组件卸载时执行,相当于componentWillUnmount。例如: ``` import { useEffect } from "react"; useEffect(() => { return () => { console.log('组件卸载'); } }, []); ``` 如果不传递第二个参数,每次组件渲染都会运行useEffect,这可能会导致无限循环。因此,在使用useEffect时,建议总是传递第二个参数来明确指定依赖项。例如: ``` import { useEffect } from "react"; useEffect(() => { console.log(props.number); setNumber(props.number); }, [props.number]); // 只有当props.number发生变化时才会执行 ``` 需要注意的是,useEffect中的副作用操作是异步执行的,不会阻塞组件的渲染过程。同时,useEffect返回的函数可以用于清除副作用操作产生的订阅或定时器等资源,以避免内存泄漏。 综上所述,useEffectReact中用于处理副作用操作的重要Hook函数,可以模拟类组件的生命周期方法,并通过传递第二个参数来控制副作用操作的执行时机。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [react中的useEffect](https://blog.youkuaiyun.com/weixin_45289656/article/details/129139932)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [react useEffect详解](https://blog.youkuaiyun.com/weixin_45760365/article/details/124386573)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值