ReactNative进阶(三十):Component和PureComponent解析

举报
SHQ1874009 发表于 2021/05/20 02:01:49 2021/05/20
【摘要】 文章目录 前言区别PureComponent缺点PureComponent优势 前言 React.PureComponent 与 React.Component 几乎完全相同,但 React.PureComponent 通过props和state的浅对比来实现 shouldComponentUpate()。 在PureComponent...


前言

React.PureComponentReact.Component 几乎完全相同,但 React.PureComponent 通过propsstate的浅对比来实现 shouldComponentUpate()

PureComponent中,如果包含比较复杂的数据结构,可能会因深层的数据不一致而产生错误的否定判断,导致界面得不到更新。

如果定义了 shouldComponentUpdate(),无论组件是否是 PureComponent,它都会执行shouldComponentUpdate(),并根据结果来判断是否 update。如果组件未实现 shouldComponentUpdate() ,则会判断该组件是否是 PureComponent,如果是的话,会对新旧 propsstate 进行 shallowEqual 比较,一旦新旧不一致,会触发 update

浅对比:通过遍历对象上的键执行相等性,并在任何键具有参数之间不严格相等的值时返回false。 当所有键的值严格相等时返回true。

区别

PureComponent自带通过propsstate的浅对比来实现 shouldComponentUpate(),而Component没有。

PureComponent缺点

可能会因深层的数据不一致而产生错误的否定判断,从而shouldComponentUpdate结果返回false,界面得不到更新。

PureComponent优势

不需要开发者自己实现shouldComponentUpdate,就可以进行简单的判断来提升性能。

为什么PureComponent比较复杂的数据结构,可能会因深层的数据不一致而产生错误的否定判断?
JavaScript 中的对象一般是可变的(Mutable),因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。如 foo={a: 1}; bar=foo; bar.a=2 你会发现此时 foo.a 也被改成了 2。

为了解决这个问题,一般的做法是使用 shallowCopy(浅拷贝)或 deepCopy(深拷贝)来避免被修改,但这样做造成了 CPU 和内存的浪费

接下来分析shallowEqual()函数

function shallowEqual(objA: mixed, objB: mixed): boolean {
  // 首先对两个基本数据类型进行比较
  if (is(objA, objB)) { return true;
  } // 判断两个数据都为object的情况
  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false;
  } // 获得所有的key
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB); // 判断两者key的数量是否一致
  if (keysA.length !== keysB.length) { return false;
  } // 如果key数量相同,使用一层for循环去比较
  for (let i = 0; i < keysA.length; i++) { if ( // 判断对象B中是否包含对象A的key,即两者的keys是否一致 !hasOwnProperty.call(objB, keysA[i]) || // 通过is()函数对比AB的key对应的数据 !is(objA[keysA[i]], objB[keysA[i]]) ) { return false; }
  }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

下面以组件的使用来举例:

例如:

class ChildComponent extends React.PureComponent {
  render() { return( <div> {this.props.numbers} </div> )
  }
}
class MainComponent extends React.Component {
  constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); this.state = { numbers: [0] }
  }
  handleClick() { const arr = this.state.numbers; arr.push(1); this.setState({ numbers: arr }) console.log(this.state.numbers)
  }
  render() { <div> <button onClick={this.handleClick} /> <ChildComponent numbers={this.state.numbers}/> </div>
  }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

在MainComponent中去修改numbers时,ChildComponent并没有得到刷新。原因在于js使用的是引用赋值,新的对象简单引用了原始对象,改变新对象虽然影响了原始对象,但对象的地址还是一样,使用===比较的方式相等。而在PureComponent中,会被判定prop相等而不触发render()

避免此类问题最简单的方式是,避免使用值可能会突变的属性或状态,而是使用副本来返回新的变量。

handleClick() {
  this.setState(prevState => ({ numbers: [...prevState.numbers, 1],
  }));
};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

文章来源: shq5785.blog.csdn.net,作者:No Silver Bullet,版权归原作者所有,如需转载,请联系作者。

原文链接:shq5785.blog.csdn.net/article/details/117032817

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。