Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

总结:React性能优化与Immutable数据流 #21

Open
lazyken opened this issue Jul 16, 2020 · 0 comments
Open

总结:React性能优化与Immutable数据流 #21

lazyken opened this issue Jul 16, 2020 · 0 comments

Comments

@lazyken
Copy link
Owner

lazyken commented Jul 16, 2020

一、对象的引用

通过一个例子说明对象对一些特性:

var obj1 = new Object()
var obj2 = obj1
obj1.name = "lazyken"
alert(obj2.name)  // "lazyken"

首先,变量 obj1 保存了一个对象的新实例。然后,这个值被复制到了 obj2 中;本质上,obj1和 obj2 都指向同一个对象,他们都保存了对同一个对象实例的引用。这样,当为 obj1 添加 name 属性后,可以通过 obj2 来访问这个属性,因为这两个变量引用的都是同一个对象。

二、React性能优化-shouldComponentUpdate、React.PureComponent、React.memo

从渲染机制上来说,当一个组件的 props 或 state 变更,React 会将最新返回的元素与之前渲染的元素进行对比,以此决定是否有必要更新真实的 DOM。当它们不相同时,React 会更新该 DOM。

1、shouldComponentUpdate

shouldComponentUpdate会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方 法。
当使用setState修改state或者组件的props更新时,默认情况下,组件始终会更新。因为react组件默认的shouldComponentUpdate始终会返回true。
在做性能优化时,当我们知道在一定条件下不需要更新组件时,我们可以指定shouldComponentUpdate返回false来跳过整个渲染过程。

2、React.PureComponent

大部分情况下,也可以用React.PureComponent代替shouldComponentUpdate。React.PureComponent会把当前与之前 props 和 state 进行浅比较来判断是否需要更新组件。
浅比较可以理解为,仅比较对象的第一层属性。但是它也会存在一些问题。当 props 或者 state 某种程度是可变的话,浅比较会有遗漏,那你就不能使用它了。看一下官方文档的例子:

class ListOfWords extends React.PureComponent {
  render() {
    return <div>{this.props.words.join(',')}</div>;
  }
}

class WordAdder extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      words: ['marklar']
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // 这部分代码很糟,而且还有 bug
    const words = this.state.words;
    words.push("marklar");
    this.setState({words: words});
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick} />
        <ListOfWords words={this.state.words} />
      </div>
    );
  }
}

它的问题在于 PureComponent 仅仅会对新老 this.props.words (props的第一层属性)的值进行简单的对比。由于代码中 WordAdder 的 handleClick 方法改变了同一个 words 数组,使得新老 this.props.words 比较的其实还是同一个数组。即便实际上数组中的单词已经变了,但是比较结果是相同的。可以看到,即便多了新的单词需要被渲染, ListOfWords 却并没有被更新。

三、React.memo

React.memo 为高阶组件。它与 React.PureComponent 非常相似,但只适用于函数组件,而不适用 class 组件。
React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。
React.memo默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么需要将自定义的比较函数通过第二个参数传入来实现。

function MyComponent(props) {
  /* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
  /*
  如果把 nextProps 传入 render 方法的返回结果与
  将 prevProps 传入 render 方法的返回结果一致则返回 true,
  否则返回 false
  */
}
export default React.memo(MyComponent, areEqual);

注意
与 class 组件中 shouldComponentUpdate() 方法不同的是,如果 props 相等,areEqual 会返回 true;如果 props 不相等,则返回 false。这与 shouldComponentUpdate 方法的返回值相反。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant