[当我在用作组件回调的函数中使用setState挂钩时,我从React中收到太多重新渲染错误。
下面是一个无用的示例来演示我正在尝试做的事情。
我有一个Person对象数组和一个Pets数组。每个宠物都有一个所有者(= Person)。我想显示此人的名字和他拥有的宠物。
我遍历Persons数组,并且每个人都应该有一个TestComponent。TestComponent需要一个人的名字和一个宠物的名字。
宠物名是在回调函数getPetByOwnerName
中计算的,该函数将遍历所有宠物,并且如果给定的人名与宠物的所有者名匹配,它将返回该宠物名。
如果某人没有宠物,则应使用setPets()
将一个空的宠物对象添加到宠物列表中。
setPets()
功能内的[getPetByOwnerName
引起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
TestComponent:
import React from 'react'
const TestComponent = ({ personName, petName }) => {
return (
<React.Fragment>
<p>{personName} owns pet: {petName}</p>
</React.Fragment>
)
}
export default TestComponent
最好在使用效果中处理这种功能。您可以观察人的变化,然后相应地更新宠物。如下所示。
但是您的实际问题是在此行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]);
此外,在使用先前状态更新状态时也应注意,最好使用回调版本(请参见上面示例中更新的set pets)
由于这只是您实际问题的一个示例,因此最好在设置状态之前先插入debugger;
,然后查看为什么这么频繁设置它。