React16的memo函数有啥用

时间:2022-07-23
本文章向大家介绍React16的memo函数有啥用,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

React16的memo和PureComponent作用类似,只不过前者只适用于函数组件,后者适应于类组件。

关于两者的作用,我们先从PureComponent说起,在了解PureComponent之前要先了解shouldComponentUpdate函数,在类组件中有一个叫做shouldComponentUpdate的生命周期函数,这个函数可以通过返回true或false来决定当前组件是否重新渲染。

而PureComponent自带shouldComponentUpdate函数,PureComponent自带的shouldComponentUpdate函数会在当前组件的props或者state发生变化时,对props或者state进行浅对比,如果相同则不进行重新渲染,反之则会进行渲染。

说到这里来了解一下浅对比,啥叫浅对比呢,类似于浅拷贝,具体的内容大家可以去百度,这里不做赘述,只做简单说明,举个例子,看代码:

import React,{memo} from "react";
import ReactDOM from 'react-dom';
class CommentList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commentList: [{
        body: '大三岁', author: '张三'
      }, {
        body: '新冠病毒', author: '李四'
      }]
    }
  }

  componentWillMount() {
    setTimeout(() => {
      this.setState((prevState, props) => {
        return {
          commentList: [{
            body: '大三岁', author: '张三'
          }, {
              body: '新冠1病毒', author: '李四'
          }]
        }
      })
    }, 1000)
  }

  render() {
    return (
      <div>
        {
          this.state.commentList.map((item, index) => {
            return <Comment {...item} key={index} />
          })
        }
      </div>
    )

  }
}
function Comment(props) {
  console.log('渲染了', props)
  return <div>
    <p>{props.body}</p>
    <p>{props.author}</p>
    <p>{props.arr.length}</p>
  </div>
}

阅读源码,我们定义了两个组件,CommentList组件与Comment组件,CommentList组件内部的state是一个数组,每条数据用Comment来渲染。我们在componentWillMount设置定时器模拟数据发生变化,我们看到第二条数据的body发生变化了,所以对应的comment组件应该重新渲染,但是我们发现所有Comment组件都重新渲染了。这不利于我们页面的性能优化,咋办呢?

此时我们可以借助memo或者PureComponent来实现只让该渲染的组件渲染,啥是该渲染的组件呢?那就是props或者state发生变化的组件,那变化的标准是怎么样的呢?

来看代码,用memo来实现:

import React,{memo} from "react";
import ReactDOM from 'react-dom';
class CommentList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commentList: [{
        body: '大三岁', author: '张三' 
      }, {
        body: '新冠病毒', author: '李四' 
      }]
    }
  }

  componentWillMount() {
    setTimeout(() => {
      this.setState((prevState, props) => {
        return {
          commentList: [{
            body: '大三岁', author: '张三'
          }, {
              body: '新冠1病毒', author: '李四'
          }]
        }
      })
    }, 1000)
  }

  render() {
    return (
      <div>
        {
          this.state.commentList.map((item, index) => {
            return <Comment {...item} key={index} />
          })
        }
      </div>
    )

  }
}



function Comment(props) {
  console.log('渲染了', props)
  return <div>
    <p>{props.body}</p>
    <p>{props.author}</p>
    <p>{props.arr.length}</p>
  </div>
}

// 第一种方式 用memo包裹函数组件
Comment = memo(Comment)

用PureComponent来实现:

import React,{memo} from "react";
import ReactDOM from 'react-dom';
class CommentList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commentList: [{
        body: '大三岁', author: '张三' 
      }, {
        body: '新冠病毒', author: '李四' 
      }]
    }
  }

  componentWillMount() {
    setTimeout(() => {
      this.setState((prevState, props) => {
        return {
          commentList: [{
            body: '大三岁', author: '张三'
          }, {
              body: '新冠1病毒', author: '李四'
          }]
        }
      })
    }, 1000)
  }

  render() {
    return (
      <div>
        {
          this.state.commentList.map((item, index) => {
            return <Comment {...item} key={index} />
          })
        }
      </div>
    )

  }
}

class Comment extends React.PureComponent {
  constructor() {
    super()
  }
  render() {
    console.log('渲染了')
    const props = this.props
    return <div>
      <p>{props.body}</p>
      <p>{props.author}</p>
    </div>
  }
}

阅读源码,我们分别用memo和PureComponent改造了代码,并且运行的话,只有该渲染的组件发生了渲染。

渲染的组件前后的props发生变化的组件才会重新渲染,来看一下props或者state发生变化的标准:

{body: '新冠病毒', author: '李四'} 

{body: '新冠1病毒', author: '李四'} 

上面两个对象进行浅对比body发生变化,所以会渲染,而另一个组件数据没变所以没有重新渲染,从而提高了页面性能。

以上便是memo的作用了,但是这里有一个问题,那就是如果props中的某一个属性是引用数据类型,这个引用数据发生改变,但是引用未变,组件是不会重新渲染的,首先我们看下不使用memo的代码:

import React,{memo} from "react";
import ReactDOM from 'react-dom';
class CommentList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commentList: [{
        body: '大三岁', author: '张三',arr:[]
      }, {
        body: '新冠病毒', author: '李四',arr:[]
      }]
    }
  }

  componentWillMount() {
    setTimeout(() => {
      this.state.commentList[0].arr.push(999)
      this.setState({ commentList: this.state.commentList})
    }, 1000)
  }

  render() {
    return (
      <div>
        {
          this.state.commentList.map((item, index) => {
            return <Comment {...item} key={index} />
          })
        }
      </div>
    )

  }
}

// 

function Comment(props) {
  console.log('渲染了', props)
  return <div>
    <p>{props.body}</p>
    <p>{props.author}</p>
    <p>{props.arr.length}</p>
  </div>
}

上面的代码,我们没有使用memo,Comment的props发生变化后,所有的Comment组件都重新渲染了,如图:

效果截图

上图红框处显示了组件重新渲染了,然后我们用memo改造代码:

import React,{memo} from "react";
import ReactDOM from 'react-dom';
class CommentList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commentList: [{
        body: '大三岁', author: '张三',arr:[]
      }, {
        body: '新冠病毒', author: '李四',arr:[]
      }]
    }
  }

  componentWillMount() {
    setTimeout(() => {
      this.state.commentList[0].arr.push(999)
      this.setState({ commentList: this.state.commentList})
    }, 1000)
  }

  render() {
    return (
      <div>
        {
          this.state.commentList.map((item, index) => {
            return <Comment {...item} key={index} />
          })
        }
      </div>
    )

  }
}

// 

function Comment(props) {
  console.log('渲染了', props)
  return <div>
    <p>{props.body}</p>
    <p>{props.author}</p>
    <p>{props.arr.length}</p>
  </div>
}


Comment = memo(Comment)

此时看效果:

效果截图

上图展示显示了,虽然组件的props发生了变化,但是组件为重新渲染。

那这个bug怎么解决呢,很简单,不要直接修改完数据直接使用,而是修改完后深拷贝一下再去调用setState。

所以在使用memo和PureComponent时大家需要特别注意,总结一下:

1、memo和PureComponent的作用提高渲染性能,避免不必要的渲染。

2、memo和PureComponent的原理是通过浅拷贝来实现的。

3、通过案例演示了memo的作用。

4、memo的缺点,当props或state中的属性有引用属性时需要注意,修改完成后进行一下深拷贝在调用setState。

以上便是使用memo的一下注意事项,希望对你有所帮助。

参考:你真的了解浅比较么?