【问题标题】:React.memo Not Preventing Re-renders of Stateless Functional Child Component that Takes In No PropsReact.memo 不阻止重新渲染不接受任何道具的无状态功能子组件
【发布时间】:2020-11-29 23:43:44
【问题描述】:

我有一个无状态功能组件(参见下面的Title),它使用 React-Reveal 在渲染时显示一些简单的标题元素。除了没有内部状态之外,Title 也不会从其父组件(GameHeader)接收任何道具。但是由于某种原因,每当我从树中其他地方的另一个不相关组件更新整体应用程序状态时,Title 仍然会不断重新渲染,这会导致 React-Reveal 动画每次运行一次不相关的应用状态更改。

// GameHeader.js
 
import React from 'react';
import Title from './Title';
import Options from './Options';
 
const GameHeader = () => {
    return (
        <div>
            <Title />
            <Options />
        </div>
    );
}
 
export default GameHeader;
 
 
// Title.js --> this component needs to stop re-rendering so much because it contains entrance animations
 
import React from 'react';
import { Typography } from '@material-ui/core';
import { useTheme } from '@material-ui/core/styles';
import Zoom from 'react-reveal/Zoom';
import Slide from 'react-reveal/Slide';
import Flip from 'react-reveal/Flip';
 
const Title = () => {
    console.log("Title rendering");
    const theme = useTheme();
 
    return (
        <>
            <Typography variant="subtitle1" color="primary">
                <Slide left>Sample</Slide>
            </Typography>
            <Typography variant="h1" style={{ color: `${theme.palette.indigo.main}` }}>
                <Flip delay={800} duration={600} cascade>App</Flip>
            </Typography>
            <Typography variant="h2" style={{ color: `${theme.palette.orange.dark}` }}>
                <Zoom delay={1100} cascade>Title</Zoom>
            </Typography>
        </>
    );
}
 
export default React.memo(Title);

我尝试在 React.memo 中包装 Title 或将其转换为 PureComponent,但无济于事 - 它仍然会不断地重新渲染和重新触发其动画。我正在使用 hooks + Context API (w/useReducer & dispatch) 来更新应用程序中其他地方的应用程序状态,但我没有直接在 GameHeader 或 em> 标题。

我怀疑因为 React.memo/PureComponent 仅在 state 和 props 之间进行浅比较,所以可能存在 phantom prop 或渲染之间不等效的东西仍然传递到 Title强>不知何故??但我不知道为什么会这样,或者如何确认或解决这个问题。或者我只是错误地使用了 React.memo?

我知道子级在父状态更改时重新渲染正是 React 的工作原理,但我需要一种方法来防止我的转换在不相关的状态更改后触发,而 React.memo 似乎并没有起到作用。有什么想法吗?

【问题讨论】:

  • 如果真的没有道具,那么React.memo 进行浅层比较的事实将是无关紧要的,因为它实际上没有比较任何东西。这里的一种选择是它正在重新安装,尽管我们不知道祖先组件或它们是如何工作的。如果动画只应该在 on mount 上播放,这也是有意义的
  • 谢谢@Jayce444。它似乎正在重新安装,因为当我使用控制台日志语句和空的依赖项 [] 参数将 useEffect 添加到“标题”时,每次我的状态更改时都会收到控制台记录的语句。我真的不确定为什么会发生这种情况,但我现在正在梳理所有的父结构,看看我是否能解决这个问题。在那种情况下,我想 React.memo 也帮不了我。
  • 是的,我也是这么想的。假设您没有通过使用诸如随机的key 道具手动触发重新安装,那么答案几乎肯定会是该组件树上某处的祖先之一正在重新安装。将不得不在树上找到它,然后调试它。应该解决这个问题

标签: javascript reactjs


【解决方案1】:

追溯它的树让我找到了解决方案。事实证明,当我删除样式组件包装器时,我在 GameHeader 周围使用的 Material UI 样式组件包装器导致 GameHeader 每次都重新安装,GameHeader 停止重新安装。 Title 也是如此,尽管在我上面展示的示例中,我已经从该组件周围移除了样式化组件包装器。

这些 MUI 样式的组件定义位于我的父功能组件中(因为它们使用了 useTheme),所以我最终做的是将这些 MUI 样式的组件定义移到父功能组件之外(在 export default 语句之后) 并且无论出于何种原因,完全解决了这个问题。

感谢 @Jayce444 为我指明了正确的方向!

【讨论】:

  • 我正在努力解决一个类似的问题,即即使没有道具更改,组件仍会使用 react memo 重新渲染,你提到你追溯了树,你是怎么做到的?谢谢。
猜你喜欢
  • 2020-10-21
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 2023-02-15
  • 2021-10-15
  • 2021-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多