如何停止 Accordion 中 AccordionBody 组件的递归渲染?
How do I stop recursive renders of a AccordionBody component inside a Accordion?
我有一个 <Accordion/>
组件可以容纳多个 <AccordionItem/>
组件。我准备了一个codesandbox demo here.
目前的问题是,在初始渲染时,所有 <AccordionItem/>
组件都被渲染(检查 codesandbox 示例中的控制台日志)。因此,根据 <Accordion/>
组件用于渲染所有项目的数组大小,这意味着需要进行大量初始渲染。此外,每次 <AccordionItem/>
是 openend 时,<Accordion/>
中的所有项目都会再次重新呈现。为了性能起见,这可能不是只有少数项目的问题。但是,在我的应用程序中,这可以是 10 <AccordionItem/>
个组件 ,它们本身具有嵌套的手风琴 ,每次用户打开一个时,它们都会不断重新呈现。所以这可能意味着每次用户打开一个项目时,都会发生 50 次左右的重新呈现。
我已经尝试了很多方法来消除这个问题。例如,手风琴依赖于 active
布尔值。因此,仅当此 active
布尔值为真时渲染手风琴主体即可消除问题,如下所示:
<div className="answer">{active && <AccordionBody />}</div>
但是,下拉动画停止工作,主体没有完全打开。我该怎么做才能在保持漂亮的下拉动画的同时只渲染点击的 <AccordionItem/>
及其主体?
一般来说,你应该让 React 在需要重新渲染时重新渲染。
您错误地将 AccordionBody
组件的函数体中的控制台日志记录为无意的副作用,但是,即使将控制台日志移至 useEffect
( 召回useEffect
钩子每次渲染调用一次 ) AccordionBody
仍然作为 Accordion
组件的一部分再次重新渲染,当状态更新时重新渲染 faqs
数组。
React 组件在 state 或 props 更新时重新渲染,或者当它们的父组件重新渲染时。当一个组件重新渲染时,它必然会重新渲染它的整个组件子树(即它的子树)。
这些额外的重新渲染通常成本低廉,不一定是一个单独的问题。这实际上取决于每个被重新渲染的组件在重新渲染时做了什么。 不要过早优化!
如果有问题,您可以用来帮助提高性能的工具是记忆道具,即使用 useMemo
或 useCallback
来提供稳定的道具参考。
您还可以使用 memo 高阶组件记忆组件。鉴于组件从相同的道具渲染相同的结果,您可以记住渲染的结果。在您的示例 codesandbox 中,这消除了重复的重新渲染。
手风琴体
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
注意:不要过早优化,只有在发现渲染或性能问题时才考虑优化。这通常视具体情况而定。
我有一个 <Accordion/>
组件可以容纳多个 <AccordionItem/>
组件。我准备了一个codesandbox demo here.
目前的问题是,在初始渲染时,所有 <AccordionItem/>
组件都被渲染(检查 codesandbox 示例中的控制台日志)。因此,根据 <Accordion/>
组件用于渲染所有项目的数组大小,这意味着需要进行大量初始渲染。此外,每次 <AccordionItem/>
是 openend 时,<Accordion/>
中的所有项目都会再次重新呈现。为了性能起见,这可能不是只有少数项目的问题。但是,在我的应用程序中,这可以是 10 <AccordionItem/>
个组件 ,它们本身具有嵌套的手风琴 ,每次用户打开一个时,它们都会不断重新呈现。所以这可能意味着每次用户打开一个项目时,都会发生 50 次左右的重新呈现。
我已经尝试了很多方法来消除这个问题。例如,手风琴依赖于 active
布尔值。因此,仅当此 active
布尔值为真时渲染手风琴主体即可消除问题,如下所示:
<div className="answer">{active && <AccordionBody />}</div>
但是,下拉动画停止工作,主体没有完全打开。我该怎么做才能在保持漂亮的下拉动画的同时只渲染点击的 <AccordionItem/>
及其主体?
一般来说,你应该让 React 在需要重新渲染时重新渲染。
您错误地将 AccordionBody
组件的函数体中的控制台日志记录为无意的副作用,但是,即使将控制台日志移至 useEffect
( 召回useEffect
钩子每次渲染调用一次 ) AccordionBody
仍然作为 Accordion
组件的一部分再次重新渲染,当状态更新时重新渲染 faqs
数组。
React 组件在 state 或 props 更新时重新渲染,或者当它们的父组件重新渲染时。当一个组件重新渲染时,它必然会重新渲染它的整个组件子树(即它的子树)。
这些额外的重新渲染通常成本低廉,不一定是一个单独的问题。这实际上取决于每个被重新渲染的组件在重新渲染时做了什么。 不要过早优化!
如果有问题,您可以用来帮助提高性能的工具是记忆道具,即使用 useMemo
或 useCallback
来提供稳定的道具参考。
您还可以使用 memo 高阶组件记忆组件。鉴于组件从相同的道具渲染相同的结果,您可以记住渲染的结果。在您的示例 codesandbox 中,这消除了重复的重新渲染。
手风琴体
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
注意:不要过早优化,只有在发现渲染或性能问题时才考虑优化。这通常视具体情况而定。