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

2022-08-30 03:02:13

我最近一直在玩 React,我喜欢 React Memo 的想法,但是我一直找不到任何最适合实现它的场景。16.6.0

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包装一个功能组件?


答案 1

您应该始终使用字面意思,因为比较组件返回的树总是比比较一对属性更昂贵React.memoprops

因此,不要听任何人的话,并将所有功能组件包装在. 最初打算内置于功能组件的核心中,但由于失去向后兼容性,默认情况下不使用。(因为它表面上比较了对象,并且您可能正在使用组件中子对象的嵌套属性) =)React.memoReact.memo

就是这样,这是 React 不使用 memo Automatically 的唯一原因。=)

实际上,他们可以制作版本17.0.0,这将破坏向后兼容性,并使其成为默认值,并创建某种功能来取消此行为,例如React.memoReact.deepProps =)

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

如果你的组件使用DEEP COMPARE PROPS,那么不要使用memo,否则总是使用它,比较两个对象总是比调用和比较两棵树,创建FiberNodes等便宜。React.createElement()

理论家谈论他们自己不知道的东西,他们没有分析反应代码,他们不了解FRP,他们不明白他们的建议=)

P.S. 如果你的组件使用 prop,将不起作用,因为 prop 总是会生成一个新的数组。但最好不要为此烦恼,甚至这些组件也应该包装在 中,因为计算资源可以忽略不计。childrenReact.memochildrenReact.memo


答案 2

所有 react 组件都实现了该方法。默认情况下(扩展组件),这将始终返回 true。记忆组件(通过功能组件或扩展类组件)引入的变化是方法的实现 - 它对状态和 props 进行了浅层比较。shouldComponentUpdate()React.ComponentReact.memoReact.PureComponentshouldComponentUpdate()

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

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

为了回答你的问题,我认为没有一个明确的规则,当你应该或不应该记住组件时,但是我认为应该应用与决定是否应该覆盖相同的原则:通过建议的分析工具发现性能问题,并确定是否需要优化组件。shouldComponentUpdate()