在回调函数中使用 setState 挂钩时反应过多的重新渲染
Posted
技术标签:
【中文标题】在回调函数中使用 setState 挂钩时反应过多的重新渲染【英文标题】:React Too many re-renders when using setState hook inside callback function 【发布时间】:2020-09-07 08:32:06 【问题描述】:当我在用作组件回调的函数中使用 setState 钩子时,我从 React 收到 Too many re-renders 错误。
下面是一个无用的示例来演示我正在尝试做的事情。
我有一个 Person 对象数组和一个 Pets 数组。每只宠物都有一个主人(=人)。 我想显示此人的姓名和他拥有的宠物。
我遍历 Persons 数组,每个人都应该有一个 TestComponent。 TestComponent 需要一个人的名字和一个宠物的名字。
宠物名称在回调函数getPetByOwnerName
中计算,它将遍历所有宠物,如果给定的人名与宠物的主人名匹配,它将返回该宠物名。
如果一个人没有宠物,它应该使用setPets()
将一个空的宠物对象添加到宠物列表中。
getPetByOwnerName
函数内的setPets()
导致Too many re-renders
错误。
在这个例子中这样做可能没有任何意义,但它是为了重现我在一个更大的项目中遇到的问题。
import React, useState from 'react'
import TestComponent from './TestComponent'
const TestPage = () =>
const [persons, setPersons] = useState([name: 'Tom', age: 35, name: 'Fred', age: 50 ])
const [pets, setPets] = useState([owner: 'Tom',name: 'Doggo'])
const getPetByOwnerName = (name) =>
let petName = null
pets.map((pet, index) =>
if (pet.owner === name)
petName = pet.name
return pet
)
if (!petName)
const pet =
owner: name,
name: ''
const updatedPets = pets
pets.push(pet)
setPets(updatedPets)
return petName
return (
<React.Fragment>
persons.map((person, index) => (
<TestComponent key=index personName=person.name petName=getPetByOwnerName(person.name)></TestComponent>
))
</React.Fragment>
)
export default TestPage
测试组件:
import React from 'react'
const TestComponent = ( personName, petName ) =>
return (
<React.Fragment>
<p>personName owns pet: petName</p>
</React.Fragment>
)
export default TestComponent
【问题讨论】:
【参考方案1】:在使用效果中处理这种功能可能会更好。您可以观察人员的变化,然后相应地更新宠物。如下所示。
但你的实际问题在这一行if (!petName)
。当 petName 是一个空字符串时,它会进入这里并永远设置状态。你需要像if(!petName && petName !== '')
这样的支票
useEffect(() =>
persons.map(person =>
const petIndex = pets.findIndex(p => p.owner === person.name);
if (petIndex === -1)
const pet =
owner: person.name,
name: ''
setPets(prevPets => ([...prevPets, pet]))
)
, [persons]);
另外,在使用之前的状态更新状态时,最好使用回调版本(参见上面示例中更新的设置宠物)
由于这只是您的实际问题的一个示例,因此最好在您设置状态之前输入debugger;
,并了解您为什么如此频繁地设置它。
【讨论】:
以上是关于在回调函数中使用 setState 挂钩时反应过多的重新渲染的主要内容,如果未能解决你的问题,请参考以下文章