【问题标题】:How do I stop recursive renders of a AccordionBody component inside a Accordion?如何停止 Accordion 内的 AccordionBody 组件的递归渲染?
【发布时间】:2021-12-09 15:32:31
【问题描述】:

我有一个<Accordion/> 组件,它可以容纳多个<AccordionItem/> 组件。我准备了codesandbox demo here

目前的问题是在初始渲染时,所有<AccordionItem/> 组件都被渲染(检查代码框示例中的控制台日志)。因此,根据 <Accordion/> 组件用于渲染所有项目的数组大小,这意味着很多初始渲染。此外,每次打开 <AccordionItem/> 时,<Accordion/> 内的所有项目都会重新渲染。出于性能考虑,这可能不是几个项目的问题。但是,在我的应用程序中,这可能是 10 个<AccordionItem/> 组件它们自己有一个嵌套的手风琴,每次用户打开它们时都会不断地重新渲染。所以这可能意味着每次用户打开一个项目时,都会发生大约 50 次重新渲染。

我已经尝试了很多方法来消除这种情况。例如,手风琴依赖于 active 布尔值。因此,只有当 active 布尔值为 true 时才渲染手风琴的主体才能消除问题,如下所示:

<div className="answer">{active && <AccordionBody />}</div>

但是,下拉动画停止工作并且body没有完全打开。我该怎么做才能只渲染点击的&lt;AccordionItem/&gt; 及其主体,同时保持漂亮的下拉动画?

【问题讨论】:

  • “所以这可能意味着每次用户打开一个项目,大约会发生 50 次重新渲染。”为什么会出现问题?
  • 我在您的代码和框中没有看到任何控制台日志。那里的代码似乎可以毫无问题地运行。您可以编辑沙盒以重现您的问题吗?
  • 嗨@DrewReese。我更新了代码框 (codesandbox.io/s/aged-shape-bc32x)。对不起,今天早上我很着急。如果每次打开一个项目时都渲染所有组件,也许这甚至不是问题。它似乎有点递归。
  • @DennisVash 好吧,我不知道是不是有问题。也许它极大地减慢了我的应用程序,也许不是。无论如何,这似乎是不必要的,并且是可以预防的。我只是不知道现在如何。我对 React 的经验还不是很丰富,所以如果你说我不应该太担心它,那也没关系。

标签: javascript html reactjs performance jsx


【解决方案1】:

一般来说,你应该让 React 在需要重新渲染时重新渲染。

您错误地将控制台日志记录在 AccordionBody 组件的函数体中,这是一种无意的副作用,但是,即使将控制台日志移动到 useEffect 之后也是如此(回想一下,useEffect 钩子被调用了一次每个渲染AccordionBody 仍然作为Accordion 组件的一部分再次重新渲染,当状态更新时重新渲染faqs 数组。

当 state 或 props 更新,或者当它们的父组件重新渲染时,React 组件会重新渲染。当一个组件重新渲染时,它必然会重新渲染它的整个组件子树(即它的子树)。

这些额外的重新渲染通常很便宜,不一定是单独的问题。这实际上取决于被重新渲染的每个组件在重新渲染时所做的事情。 不要过早优化!

如果出现问题,您可以用来帮助提高性能的工具是记忆道具,即使用useMemouseCallback 来提供稳定的道具参考。

您还可以使用memo 高阶组件来记忆组件。给定组件从相同的道具渲染相同的结果,您可以记住渲染的结果。在您的示例代码框中,这消除了重复的重新渲染。

手风琴体

import React, { memo, useEffect } from "react";

function AccordionBody() {
  useEffect(() => {
    console.log("AccordionBody rendered"); // <-- log once per render
  });

  return (
    <div>
      <div>All of the AccordionBody's are rendered</div>
      <div>So everytime an accordion item is openend</div>
      <div>The AccordionBody component gets rendered 3 times</div>
      <div>1 for every faq in the faqs array</div>
      <div>How will this impact performance in a large array?</div>
      <div>
        How do I stop these recursive re-renders, while maintaining the
        animation?
      </div>
    </div>
  );
}

export default memo(AccordionBody); // <-- memoize render result

注意:不要过早优化,而仅在发现渲染或性能问题时才进行优化。这通常会根据具体情况而定。

【讨论】:

    猜你喜欢
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2021-03-10
    • 2023-03-20
    • 2016-12-26
    • 2019-12-21
    • 2020-09-11
    相关资源
    最近更新 更多