Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to solve the infinite loop of React.useEffect ()

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "how to solve the infinite loop of React.useEffect()". The explanation content in this article is simple and clear, easy to learn and understand. Please follow the ideas of Xiaobian slowly and deeply to study and learn "how to solve the infinite loop of React.useEffect()" together!

1. Infinite loop and side effects update status

Suppose we have a functional component that has an input element inside, and the function of the component is to count the number of input changes.

We call this component CountInputChanges, and it looks something like this:

function CountInputChanges() { const [value, setValue] = useState(''); const [count, setCount] = useState(-1); useEffect(() => setCount(count + 1)); const onChange = ({ target }) => setValue(target.value); return ( Number of changes: {count} ) }

It's a controlled component. The value variable holds the value of input, and the onChange event handler updates the value state when the user enters input.

Here, useEffect() is used to update the count variable. useEffect(() => setCount(count + 1)) updates the counter each time the component rerenders due to user input.

Because useEffect(() => setCount(count + 1)) is used without dependent parameters,()=> setCount(count + 1) performs a callback after each rendering of the component.

Do you think that's a problem? Open the demo and try it yourself: codesandbox.io/s/infinite-loop-9rb8c? file=/src/App.js

Running it will find that the count state variable is increasing uncontrollably, even if nothing is entered in input, which is an infinite loop.

问题在于useEffect()的使用方式:

useEffect(() => setCount(count + 1));

它生成一个无限循环的组件重新渲染。

在初始渲染之后,useEffect()执行更新状态的副作用回调函数。状态更新触发重新渲染。重新渲染之后,useEffect()执行副作用回调并再次更新状态,这将再次触发重新渲染。

1.1通过依赖来解决

无限循环可以通过正确管理useEffect(callback, dependencies)依赖项参数来修复。

因为我们希望count在值更改时增加,所以可以简单地将value作为副作用的依赖项。

import { useEffect, useState } from 'react'; function CountInputChanges() { const [value, setValue] = useState(''); const [count, setCount] = useState(-1); useEffect(() => setCount(count + 1), [value]); const onChange = ({ target }) => setValue(target.value); return ( Number of changes: {count} ); }

添加[value]作为useEffect的依赖,这样只有当[value]发生变化时,计数状态变量才会更新。这样做可以解决无限循环。

1.2 使用 ref

除了依赖,我们还可以通过 useRef() 来解决这个问题。

其思想是更新 Ref 不会触发组件的重新渲染。

import { useEffect, useState, useRef } from "react"; function CountInputChanges() { const [value, setValue] = useState(""); const countRef = useRef(0); useEffect(() => countRef.current++); const onChange = ({ target }) => setValue(target.value); return ( Number of changes: {countRef.current} ); }

useEffect(() => countRef.current++) 每次由于value的变化而重新渲染后,countRef.current++就会返回。引用更改本身不会触发组件重新渲染。

2. 无限循环和新对象引用

即使正确设置了useEffect()依赖关系,使用对象作为依赖关系时也要小心。

例如,下面的组件CountSecrets监听用户在input中输入的单词,一旦用户输入特殊单词'secret',统计 'secret' 的次数就会加 1。

import { useEffect, useState } from "react"; function CountSecrets() { const [secret, setSecret] = useState({ value: "", countSecrets: 0 }); useEffect(() => { if (secret.value === 'secret') { setSecret(s => ({...s, countSecrets: s.countSecrets + 1})); } }, [secret]); const onChange = ({ target }) => { setSecret(s => ({ ...s, value: target.value })); }; return ( Number of secrets: {secret.countSecrets} ); }

打开演示(https://codesandbox.io/s/infinite-loop-obj-dependency-7t26v?file=/src/App.js)自己试试,当前输入 secret,secret.countSecrets的值就开始不受控制地增长。

这是一个无限循环问题。

为什么会这样?

secret对象被用作useEffect(..., [secret])。在副作用回调函数中,只要输入值等于secret,就会调用更新函数

setSecret(s => ({...s, countSecrets: s.countSecrets + 1}));

这会增加countSecrets的值,但也会创建一个新对象。

secret现在是一个新对象,依赖关系也发生了变化。所以useEffect(..., [secret])再次调用更新状态和再次创建新的secret对象的副作用,以此类推。

JavaScript 中的两个对象只有在引用完全相同的对象时才相等。

2.1 避免将对象作为依赖项

解决由循环创建新对象而产生的无限循环问题的最好方法是避免在useEffect()的dependencies参数中使用对象引用。

let count = 0;

useEffect(() => {

// some logic

}, [count]); // Good!

let myObject = { prop: 'Value' }; useEffect(() => { // some logic }, [myObject]); // Not good! useEffect(() => { // some logic }, [myObject.prop]); // Good!

修复组件的无限循环问题,可以将useEffect(..., [secret])) 变为 useEffect(..., [secret.value])。

仅在secret.value更改时调用副作用回调就足够了,下面是修复后的代码:

import { useEffect, useState } from "react"; function CountSecrets() { const [secret, setSecret] = useState({ value: "", countSecrets: 0 }); useEffect(() => { if (secret.value === 'secret') { setSecret(s => ({...s, countSecrets: s.countSecrets + 1})); } }, [secret.value]); const onChange = ({ target }) => { setSecret(s => ({ ...s, value: target.value })); }; return ( Number of secrets: {secret.countSecrets} ); }3 总结

useEffect(callback, deps)是在组件渲染后执行callback(副作用)的 Hook。如果不注意副作用的作用,可能会触发组件渲染的无限循环。

生成无限循环的常见情况是在副作用中更新状态,没有指定任何依赖参数

useEffect(() => { // Infinite loop! setState(count + 1); });

避免无限循环的一种有效方法是正确设置依赖项:

useEffect(() => { // No infinite loop setState(count + 1); }, [whenToUpdateValue]);

另外,也可以使用 Ref,更新 Ref 不会触发重新渲染:

useEffect(() => { // No infinite loop countRef.current++; });

无限循环的另一种常见方法是使用对象作为useEffect()的依赖项,并在副作用中更新该对象(有效地创建一个新对象)

useEffect(() => { // Infinite loop! setObject({ ...object, prop: 'newValue' }) }, [object]);

避免使用对象作为依赖项,只使用特定的属性(最终结果应该是一个原始值):

useEffect(() => { // No infinite loop setObject({ ...object, prop: 'newValue' }) }, [object.whenToUpdateProp]);

当使用useEffect()时,你还知道有其它方式会引起无限循环陷阱吗?

感谢各位的阅读,以上就是"怎么解决React.useEffect()的无限循环"的内容了,经过本文的学习后,相信大家对怎么解决React.useEffect()的无限循环这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report