PureComponent 的正确打开方式

React 提供了 PureComponent 之后,我们知道 PureComponent 对性能有一定的提升,但是不是所有组件都应该用 PureComponent?

 

与 Component 的区别

PureComponent  与 Component  的唯一差别就在于:PureComponent  帮你做了 shouldComponentUpdate  的判断。

 

shouldComponentUpdate(nextProps, nextState){
  return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
}

 

shouldComponentUpdate 决定了组件是否调用 render 函数重新进行渲染。

 

上面这段代码的含义为:当新的 props (即 nextProps)或新的 state (即 nextState)与当前的值相比没有发生变化时,组件不用更新。这里我们用 shallowEqual,只比较 object 的第一层 key value,因为进行 deepEqual 的对比是非常耗性能的。

 

 

正确传递 props

由 shallowEqual 引申出来的是 js 中对象的值比对问题。

 

const newObject = this.state.obj
newObject.id = 2;

this.setState({
  obj: newObject,
});

 

试想如果我们这样更新 state 之后,继承自 PureComponent 的组件会不会更新?

 

 

--- 🤤 ---

 

 

答案是不会。原因在于:newObject 与 this.state.obj 始终指向同一个内存地址,所以当我们用 shallowEqual 对比 this.state 与 nextState 时,得到的结果是二者相等。也就意味着 PureComponent 不会执行 render。

 

所以我们一般会这样写:

 

const newObject = {
  ...this.state.obj,
  id: 2,
};

this.setState({
  obj: newObject,
});

this.state.obj === nextState.obj; // false

 

 

于是发展到后来,我们有了 Immutable 的概念:「当一个数据被创建之后,就永远不会变了」。如果需要更新这个数据,你必须重新创建一个。

 

const obj = {
  id: 1,
  text: 'hello',
};

obj.text = 'world' // 这样不行,obj 不可被改变


// 你必须要像这样创造一个新的数据
const newObj = {
  ...obj,
  text: 'world',
};

 

 

这样始终保证新传入的 props 或 state 都是新的对象, shallowEqual 就不会再出错了。

 

 

--- 😪 ---

 

 

一个对象指向同一个引用地址会导致 PureComponent 不更新,相反的,每次都传入一个新对象就会导致 PureComponent 每次都执行 render,与 Component 也就不再有区别。

有下面几种情况会导致 props 每次都传入一个新对象。

 

  • bind a function

 

<CommentItem likeComment={() => this.likeComment(user.id)} />

 

  • 在 render 中生成新对象往子组件中传递

 

render() {
  const { posts } = this.props;
  const topTen = [...posts].sort((a, b) => 
    b.likes - a.likes).slice(0, 9);
  return (
    <Posts items={topTen} />
  );
}

 

  • someArray || [], someObject || {}, ...

 

render() {
  const { posts } = this.props;
  // 当 posts == false 时,传入 [] 相当于每次都传入一个新对象
  return (
    <Posts items={posts || []} />
  );
}

 

 

小心踩坑

所以最后,灵魂拷问:是不是应该总是优先使用 PureComponent 而不是 Component ?

 

这里有两个坑需要注意一下。

 

  • 子组件也需要是纯组件

官方文档中有一句话:

 

Make sure all the children components are also “pure”.

 

父组件如果是 PureComponent,当 state 和 props 保持不变时是不会重新渲染的,子组件也就不会重新渲染了。如果你遇到 props 更新时组件无法更新,就可以排查一下是不是组件树的哪一级误用了 PureComponent。

 

  • PureComponent 是不是任何情况下都比 Component 性能好?

 

看一个比较常见的例子:

 

render() {
  const { item } = this.props;
  return <Post item={item} style={{ 'width': 120 }} />;
}

 

由于每次传入的 style 都是一个新对象,所以我们已经可以预知这个组件是每次都需要 rerender 的。此时 PureComponent 每次都要执行一次 shallowEqual 对比,反而比 Component 更消耗性能。

 

所以结论是,如果你已经预期到某个组件的 props 或是 state 会「频繁变动」,那就根本不用使用 PureComponent,因为这样反而会变慢。

 

 


 

 

相关文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值