react-native-render-html:“你好像在短时间内更新了Y分量的X prop ……”

ev7lccsx  于 2023-05-07  发布在  React
关注(0)|答案(3)|浏览(256)

我在WebDisplay组件中渲染RenderHtml组件,如下所示:

import * as React from 'react';
import {ScrollView, StyleSheet, Text, useWindowDimensions} from 'react-native';
import RenderHtml from 'react-native-render-html';

const html = '<div>Hello world!</div>';

function WebDisplay({html}) {
  const {width: contentWidth} = useWindowDimensions();
  const tagsStyles = {
    a: {
      textDecorationLine: 'none',
    },
  };
  return (
    <RenderHtml
      contentWidth={contentWidth}
      source={{html}}
      tagsStyles={tagsStyles}
    />
  );
}

export default function App() {
  const [isToastVisible, setIsToastVisible] = React.useState(false);
  React.useEffect(function flipToast() {
    const timeout = setTimeout(() => {
      setIsToastVisible((v) => !v);
    }, 30);
    return () => {
      clearTimeout(timeout);
    };
  });
  return (
    <ScrollView contentContainerStyle={styles.container}>
      <WebDisplay html={html} />
      {isToastVisible && <Text>This is a toast!</Text>}
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: {
    flexGrow: 1,
  },
});

为什么我会收到此警告,它意味着什么以及如何修复它?

idfiyjo8

idfiyjo81#

通常,在以下情况下会显示此警告:

  • 父组件(当前为App)更新非常频繁,并导致WebDisplay组件重新呈现。在提供的代码片段中,每30毫秒;
  • 在每次重新渲染之间,至少有一个传递给RenderHTML的prop是引用不稳定的。在提供的代码片段中,tagsStyles引用在每次重新呈现时都会更改。

请注意,在useEffect钩子引起的App组件的每次更新之间,传递给WebDisplayhtml prop没有改变。但是WebDisplay无论如何都会被重新渲染,因为它不是“纯”的。
出于这个原因,一个非常简单的解决方案是将WebDisplay Package 在React.memo中:

const WebDisplay = React.memo(function WebDisplay({html}) {
  const {width: contentWidth} = useWindowDimensions();
  const tagsStyles = {
    a: {
      textDecorationLine: 'none',
    },
  };
  return (
    <RenderHtml
      contentWidth={contentWidth}
      source={{html}}
      tagsStyles={tagsStyles}
    />
  );
});

您可以在官方文档中了解有关此技术的更多信息。

注意:“pure”术语来源于React PureComponent类。我认为React.pure应该比React.memo更明确,因为我们现在使用“memoization”来指定适用于组件和 prop 的优化技术,这可能会让人感到困惑。我倾向于为组件保留“纯”术语,为 prop 保留“记忆化”术语。

另一种解决方案是将tagsStyles移出WebDisplay函数体。在这种情况下,它将只示例化一次,并成为引用稳定的。因为RenderHtml本身是纯的,所以它不会重新呈现自己的子组件,并且警告应该消失:

const tagsStyles = {
  a: {
    textDecorationLine: 'none',
  },
};

function WebDisplay({html}) {
  const {width: contentWidth} = useWindowDimensions();
  return (
    <RenderHtml
      contentWidth={contentWidth}
      source={{html}}
      tagsStyles={tagsStyles}
    />
  );
};

注意:将任何不依赖于任何其他状态的prop或prop移动到函数组件主体之外是一个很好的习惯。

最后,如果你的用例涉及tagsStyles,这取决于一个prop,你可以用React.useMemo记住它:

function WebDisplay({html, anchorColor}) {
  const {width: contentWidth} = useWindowDimensions();
  const tagsStyles = React.useMemo(
    () => ({
      a: {
        color: anchorColor,
        textDecorationLine: 'none',
      },
    }),
    [anchorColor],
  );
  return (
    <RenderHtml
      contentWidth={contentWidth}
      source={{html}}
      tagsStyles={tagsStyles}
    />
  );
}

更多关于这个钩子的信息在官方文档中。
如果你仍然没有一个清晰的思维模型来理解组件更新在React中是如何工作的,我建议你阅读这些材料来提高你的技能:

fd3cxomn

fd3cxomn2#

<RenderHtml />中删除这个 prop enableExperimentalBRCollapsing={true}对我来说很有用。

2sbarzqh

2sbarzqh3#

我用iOS Home键/手势击中了这个问题--离开警告是正确的做法。发生这种情况是因为iOS在离开应用程序时更改了亮/暗模式,以便抓取屏幕截图:https://github.com/facebook/react-native/issues/28525

相关问题