在回调函数中使用 setState 钩子时反应太多重新渲染
React Too many re-renders when using setState hook inside callback function
当我在用作组件回调的函数中使用 setState 挂钩时,我从 React 收到了太多重新渲染错误。
下面是一个无用的例子来演示我正在尝试做的事情。
我有一组 Person 对象和一组 Pets。每只宠物都有一个主人(=人)。
我想显示这个人的名字和他拥有的宠物。
我遍历了 Persons 数组,每个人都应该有一个 TestComponent。
TestComponent 需要一个 Person 的名字和一个 Pet 的名字。
宠物名字是在一个回调函数中计算出来的getPetByOwnerName
,它会循环遍历所有宠物,如果给定的人物名字与宠物主人的名字相匹配,它会return那个宠物名字。
如果一个人没有宠物,它应该使用 setPets()
.
添加一个空的 Pet 对象到 Pets 列表中
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
在使用效果中处理此类功能可能更好。您可以观察人员的变化,然后相应地更新宠物。如下所示。
但您的实际问题出在这一行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 挂钩时,我从 React 收到了太多重新渲染错误。
下面是一个无用的例子来演示我正在尝试做的事情。
我有一组 Person 对象和一组 Pets。每只宠物都有一个主人(=人)。 我想显示这个人的名字和他拥有的宠物。
我遍历了 Persons 数组,每个人都应该有一个 TestComponent。 TestComponent 需要一个 Person 的名字和一个 Pet 的名字。
宠物名字是在一个回调函数中计算出来的getPetByOwnerName
,它会循环遍历所有宠物,如果给定的人物名字与宠物主人的名字相匹配,它会return那个宠物名字。
如果一个人没有宠物,它应该使用 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
在使用效果中处理此类功能可能更好。您可以观察人员的变化,然后相应地更新宠物。如下所示。
但您的实际问题出在这一行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;
,看看您为何如此频繁地设置它。