提问者:小点点

什么时候不应该使用React备忘录?


我最近一直在玩React16.6.0,我喜欢React Memo的想法,但是我找不到任何关于最适合实现它的场景的东西。

React文档(https://reactjs.org/docs/react-api.html#reactmemo)似乎并没有暗示将它扔在所有功能组件上有任何含义。

因为它做了一个肤浅的比较,以确定是否需要重新渲染,所以是否会出现对性能产生负面影响的情况?

这样的情况似乎是一个显而易见的实施选择:

// NameComponent.js
import React from "react";
const NameComponent = ({ name }) => <div>{name}</div>;
export default React.memo(NameComponent);

// CountComponent.js
import React from "react";
const CountComponent = ({ count }) => <div>{count}</div>;
export default CountComponent;

// App.js
import React from "react";
import NameComponent from "./NameComponent";
import CountComponent from "./CountComponent";

class App extends Component {
  state = {
    name: "Keith",
    count: 0
  };

  handleClick = e => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <NameComponent name={this.state.name} />
        <CountComponent count={this.state.count} />
        <button onClick={this.handleClick}>Add Count</button>
      </div>
    );
  }
}

因为name在这种情况下永远不会改变,所以记忆是有意义的。

但是,如果道具经常更换,情况又如何呢
如果我添加了另一个按钮,该按钮更改了状态中的其他内容并触发了重新渲染,那么在备忘录中包装CountComponent是否有意义,即使该组件的设计意味着要频繁更新?

我想我的主要问题是,只要一切保持纯净,是否存在不使用React Memo包装功能组件的情况?


共3个答案

匿名用户

所有的反应组件都实现了应该的ComponentUpdate()方法。默认情况下(扩展React的组件。组件),这总是返回true。为功能组件记忆组件(通过React.memo或扩展React的更改。PureComponent(类组件的PureComponent)介绍的是一个实现的方法,该方法执行状态和props的浅层比较。

查看有关组件生命周期方法的文档,在渲染发生之前总是调用shouldComponentUpdate(),这意味着在每次更新时记忆组件将包括此附加的浅层比较。

考虑到这一点,记忆组件确实会对性能产生影响,这些影响的大小应该通过分析您的应用程序并确定它是否在有记忆的情况下工作得更好来确定。

为了回答你的问题,我不认为有一个明确的规则,当你应该或不应该记忆组件,但是我认为同样的原则应该应用于决定你是否应该覆盖应该组件更新():通过建议的查找性能问题分析工具,并确定是否需要优化组件。

匿名用户

所以不要听任何人的话,把所有功能组件包装在React.memo中。React.memo最初是打算内置到功能组件的核心中,但由于默认原因,它不会被使用向后兼容性的丧失。(因为它比较表面的对象,你可能正在使用嵌套属性的子对象的组件)=)

就是这样,这是React不自动使用备忘录的唯一原因。=)

事实上,他们可以制作17.0版。0,这将破坏向后兼容性,并使做出反应。记录默认值,并使用某种函数来取消此行为,例如React。deepProps=)

别听理论家的话,伙计们=)规则很简单:

如果您的组件使用深度比较道具,那么不要使用memo,否则请始终使用它,比较两个对象总是比调用React便宜。createElement()并比较两棵树,创建纤维节点,等等。

理论家谈论他们自己不知道的东西,他们没有分析反应代码,他们不理解玻璃钢,他们不明白他们在建议什么=)

注意:如果您的组件正在使用子组件prop,React。memo将不起作用,因为子项prop总是生成一个新数组。但最好不要为此烦恼,甚至这样的组件也应该包装在React中。备注,因为计算资源微不足道。

匿名用户

是否会出现对绩效产生负面影响的情况?

对如果所有组件都被React无意识地包装,那么最终可能会导致性能下降。备忘录

很多情况下是不需要的。为了尝试使用性能关键组件,首先做一些测量,添加备忘录,然后再次测量,看看增加的复杂性是否值得。

一个记忆化的组件将旧道具与新闻道具进行比较,以决定是否重新渲染-每个渲染周期
在父级中的道具/状态更改后,普通组件不关心,只渲染。

看一下ReactshlowEqual实现,它在updateMemoComponent中调用。

没有硬性规定。影响反应的事物。备忘录消极:

  1. 组件经常用道具重新渲染,反正已经改变了
  2. 组件重新渲染很便宜
  3. 比较函数执行起来很贵

广告1:在这种情况下,React。备注无法阻止重新渲染,但必须进行其他计算<广告2:对于一个“简单”的组件来说,在渲染、协调、DOM更改和副作用成本方面,增加的比较成本是不值得的<广告3:道具越多,计算越多。您还可以传入更复杂的自定义比较器。

它只检查道具,不检查内部的上下文更改或状态更改<代码>反应。如果已记忆的组件具有非基本子项,则memo也没有用处<代码>使用备忘录可以在此处补充备忘录,如:

// inside React.memo component
const ctxVal = useContext(MyContext); // context change normally trigger re-render
return useMemo(() => <Child />, [customDep]) // prevent re-render of children