在回调函数中使用 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;,看看您为何如此频繁地设置它。