当子组件更新父组件状态时,避免父组件重新渲染。

7
在我们的React应用程序中,我们有父子组件。 子组件调用父方法来更新父状态值。 这是示例代码:
//父组件
const parent = ({ items }) => {
    const [information, setInformation] = useState([]);
    const updateParentInformation = (childUpdate) => {
         setInformation(information + childUpdates)
    }
    return (
        <div>
            <div>{information}</div>
            ...
            {items.map((item) => {
                return (
                    <ChildComponent item={item} updateParentInformation={updateParentInformation} />
            )})}
        </div>
    )
}

//子组件

const ChildComponent = ({ item, updateParentInformation }) => {
    useEffect(() => {
        const cardInformation = calculateCardInformation(item)
        updateParentInformation(cardAmpScripts)
     }, [item])
    return (
        <div>
            .....
        </div>
    )
}

所以子组件调用父亲的updateParentInformation函数来更新父组件状态,从而重新渲染父组件。这里我有几个问题。
  1. In some cases, we may have 100-150 Child components, in such cases our parents will re-render a lot, How to avoid this. We can avoid this throgh this code

    ....
     let recievedUpdates = 0
     const updateParentInformation = (childUpdate) => {
          recievedUpdates++
          if(recievedUpdates == items.length {
              setInformation(information + childUpdates)
          }
     }
    
如果这是可能的解决方案,那么我有第二个问题:
2. 当子组件调用父组件的updateParentInformation函数时,如何避免竞争条件。例如,当子组件1调用updateParentInformation函数并且同时子组件2也调用updateParentInformation函数时,在这种情况下,我们可能会丢失来自一个子组件的更新。

1
对于第一个问题,您可以使用React.memo() (https://reactjs.org/docs/react-api.html#reactmemo)来使组件只在其props更改时重新渲染。 - coglialoro
你能在codesandbox.io或类似的平台上创建一个可运行的[mcve]吗?这样我就能够让其他人看一下代码的行为了。 - a.h.g.
1个回答

6

由于组件的内部状态变化会导致重新渲染,因此您无法避免这种情况。所以在这种情况下,您有两种可能的方法来解决性能问题:

  1. 使用React.memo()包装您的子组件,这样每当您的一个子组件在父组件中更新状态时,所有不关心并且不作为prop接收到该更新状态的子组件都不会重新渲染。
  2. 使用全局状态管理器(建议)。如果有成百上千个组件使用共同状态,并且这些状态通过props进行传递,从而导致大量不必要的重新渲染,则绝对可以受益于使用状态管理器,例如Redux。这样,只有使用特定状态片段的组件在状态更改时才会重新渲染。

无论哪种方法,在树形结构中位于顶部的组件(父组件)中进行重计算时,始终将它们包装在useMemo()钩子中,函数和useCallback()也是如此。这样,您将能够解决大多数性能问题。

关于“race-condition”的问题,React useState可以像这样与回调一起使用,以确保在执行时可以访问该状态的最新值:

const [state, setState] = useState(0)
setState(currentState => currentState + 1)

为什么您建议使用像Redux这样的状态管理器而不是useMemo?这些管理器在幕后做了一些不同的事情,还是只是使实现更容易?谢谢。 - codego
1
避免不必要的渲染只是使用全局状态管理器的积极方面之一。正如我所写的,如果有数百或数千个组件共享状态,通过钻取props、使用上下文和记忆化变得完全无法维护。状态管理器做到了它们承诺的“管理应用程序状态”。在幕后,它们通常使用非常不同的技术和方法。 - Cesare Polonara

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接