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

骑猪看日落 2023-01-22 10:54 32阅读 0赞

文章目录

    • 前言
    • 区别
        • PureComponent缺点
        • 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()函数

  1. function shallowEqual(objA: mixed, objB: mixed): boolean {
  2. // 首先对两个基本数据类型进行比较
  3. if (is(objA, objB)) {
  4. return true;
  5. }
  6. // 判断两个数据都为object的情况
  7. if (typeof objA !== 'object' || objA === null ||
  8. typeof objB !== 'object' || objB === null) {
  9. return false;
  10. }
  11. // 获得所有的key
  12. const keysA = Object.keys(objA);
  13. const keysB = Object.keys(objB);
  14. // 判断两者key的数量是否一致
  15. if (keysA.length !== keysB.length) {
  16. return false;
  17. }
  18. // 如果key数量相同,使用一层for循环去比较
  19. for (let i = 0; i < keysA.length; i++) {
  20. if (
  21. // 判断对象B中是否包含对象A的key,即两者的keys是否一致
  22. !hasOwnProperty.call(objB, keysA[i]) ||
  23. // 通过is()函数对比A和B的key对应的数据
  24. !is(objA[keysA[i]], objB[keysA[i]])
  25. ) {
  26. return false;
  27. }
  28. }

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

例如:

  1. class ChildComponent extends React.PureComponent {
  2. render() {
  3. return(
  4. <div>
  5. { this.props.numbers}
  6. </div>
  7. )
  8. }
  9. }
  10. class MainComponent extends React.Component {
  11. constructor(props) {
  12. super(props);
  13. this.handleClick = this.handleClick.bind(this);
  14. this.state = {
  15. numbers: [0]
  16. }
  17. }
  18. handleClick() {
  19. const arr = this.state.numbers;
  20. arr.push(1);
  21. this.setState({
  22. numbers: arr
  23. })
  24. console.log(this.state.numbers)
  25. }
  26. render() {
  27. <div>
  28. <button onClick={ this.handleClick} />
  29. <ChildComponent numbers={ this.state.numbers}/>
  30. </div>
  31. }
  32. }

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

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

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

发表评论

表情:
评论列表 (有 0 条评论,32人围观)

还没有评论,来说两句吧...

相关阅读