【问题标题】:React rerendering children in functional component despite using memo and not having any prop changed尽管使用备忘录并且没有更改任何道具,但对功能组件中的子项做出反应
【发布时间】:2020-05-06 19:24:03
【问题描述】:

我有一个图标组件,它绘制一个图标并且它正在闪烁,因为父级正在让它重新渲染。我不明白为什么会发生这种情况以及如何防止这种情况发生。

Here is a snack 显示问题。

我们使用 setInterval 模拟父级更改。

我们通过在控制台中记录“重新渲染”来模拟图标重新渲染。

代码如下:

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';


// or any pure javascript modules available in npm
let interval = null

const Child = ({name}) => {
  //Why would this child still rerender, and how to prevent it?
  console.log('rerender')
  return <Text>{name}</Text>
}
const ChildContainer = ({name}) => {
  const Memo = React.memo(Child, () => true)
  return <Memo name={name}/>
}

export default function App() {
  const [state, setState] = React.useState(0)
  const name = 'constant'
  // Change the state every second
  React.useEffect(() => {
    interval = setInterval(() => setState(s => s+1), 1000)
    return () => clearInterval(interval)
  }, [])
  return (
    <View>
      <ChildContainer name={name} />
    </View>
  );
}

如果你能解释一下为什么会发生这种情况以及解决它的正确方法是什么,那就太棒了!

【问题讨论】:

  • 你的父组件是否不断发生一些变化?
  • 我们改变onMouseEnter和onMouseLeave的状态。这会使图标闪烁

标签: reactjs react-native react-hooks


【解决方案1】:

如果您将const Memo = React.memo(Child, () =&gt; true) 移到ChildContainer 之外,您的代码将按预期工作。

虽然ChildContainer 不是记忆组件,但它会被重新渲染,并在每次父重新渲染时创建一个记忆化的Child 组件。

通过将 memoization 移到 ChildContainer 之外,您可以安全地记住您的组件 Child 一次,并且无论 ChildContainer 被调用多少次,Child 只会运行一次。

这是一个有效的demo。我还在App 上添加了一个日志来跟踪每次重新渲染,并在ChildComponent 上添加了一个日志,因此您可以看到在每次重新渲染时都会调用此函数,而无需再实际接触Child

您也可以直接用React.memo 包裹Child

import * as React from "react";
import { Text, View, StyleSheet } from "react-native";

// or any pure javascript modules available in npm
let interval = null;

const Child = React.memo(({ name }) => {
  //Why would this child still rerender, and how to prevent it?
  console.log("memoized component rerender");
  return <Text>{name}</Text>;
}, () => true);

const ChildContainer = ({ name }) => {
  console.log("ChildContainer component rerender");
  return <Child name={name} />;
};

export default function App() {
  const [state, setState] = React.useState(0);
  const name = "constant";
  // Change the state every second
  React.useEffect(() => {
    interval = setInterval(() => setState(s => s + 1), 1000);
    return () => clearInterval(interval);
  }, []);

  console.log("App rerender");
  return (
    <View>
      <ChildContainer name={name} />
    </View>
  );
}

【讨论】:

  • 好的。非常感谢,这完美地回答了原始问题。我有一个新的,因为它仍然不能解决我的问题,因为在父级中使用 HOC 时会中断。我无法解释为什么。我会在这里链接问题。
  • 你能看看这个吗?这真的很有帮助。 stackoverflow.com/questions/61645789/…
  • @Sharcoux 非常乐意提供帮助!我也回答了你的新问题。如果还不够清楚,请告诉我是否可以提供更详细的答案。
猜你喜欢
  • 2020-09-28
  • 2020-03-23
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 2019-08-13
  • 2020-10-04
  • 2021-03-10
  • 1970-01-01
相关资源
最近更新 更多