十、React学习笔记整理(类组件的生命周期-新)

117 阅读2分钟

在React 17版本中对生命周期函数的调整

  1. 这三个钩子函数可能会被废弃
    componentWillMount
    componentWillUpdate
    componentWillReceiveProps
    如果直接使用会报警告。在使用的时候在函数前面加上UNSAFE_可以避免警告。

    废弃原因:过时的组件生命周期往往会带来不安全的编码实践。这些生命周期方法经常被误解和滥用;此外,我们预计,
    在异步渲染中,它们潜在的误用问题可能更大。我们将在即将发布的版本中为这些生命周期添加 “UNSAFE_” 前缀。
    (这里的 “unsafe” 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 bug,
    尤其是在启用异步渲染之后。)
    
  2. react 17版本另外新加了两个新的钩子函数:
    1). static getDerivedStateFromProps(): 挂载和更新时候都会触发
    2). static getSnapshotBeforeUpdate(): 更新时候才会触发

新的生命周期

一、getDerivedStateFromProps

这个钩子函数会将props中接收到的参数,自动合并到当前组件state中。
由于合并的状态是从props中获取的数据,所以合并后的状态也称为派生状态
使用时应注意以下几点:

  1. 使用时候必须使用static
  2. 必须返回一个返回值,可以是一个值 也可以 是null
  3. 这个方法使用比较罕见,除非state的值在任何时候都取决于props才会使用这个钩子函数,因此这个钩子函数也不常用。
  4. getDerivedStateFromProps合并后的派生状态,会使代码冗余,难以维护
  5. 组件挂载和更新时候都会触发这个钩子函数

二、getSnapshotBeforeUpdate

可以在组件更新之前做⼀些事情, ⼀些特殊案例会使⽤到。
此生命周期的返回值将作为第三个参数传递给 componentDidUpdate(通常不需要,但在重新渲染过程中手动保留滚动位置等情况下非常有用。

getSnapshotBeforeUpdate的使用案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>03_getSnapshotBeforeUpdate</title>
    <style>
        .list{
            width: 200px;
            height: 100px;
            background-color: #61dafb;
            overflow: auto;
        }
        /**
           var list = document.getElementsByClassName('list')[0]
           1.list.scrollTop可以获取或者设置第0位距离顶部的高度
           2.list.scrollHeight可以获取可滚动区域的高度
         */
    </style>
</head>
<body>
    <div id="test"></div>
    <script src="https://cdn.staticfile.org/react/17.0.1/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/17.0.1/umd/react-dom.development.js"></script>
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>

    <script type="text/babel">

      class NewsList extends React.Component {
        /**
         * 需求:新闻在不断地新增,需要保持当前滚动条的位置,不发生改变
         * 解决方案:现在的滚动条高度=新的滚动条高度-旧的滚动条高度
         * @type {{newsList: Array}}
         */
        state = {newsList: []}
        //组件挂载之后更新数据
        componentDidMount(){
          setInterval(()=>{
            let {newsList} = this.state
            let news = '新闻' + (newsList.length + 1);
            this.setState({newsList: [news, ...newsList]})
          }, 1000)
        }

        getSnapshotBeforeUpdate(preProps, preState){
          // 组件更新之前的高度
            let oldHeight = this.refs.list.scrollHeight
            return {oldHeight}
        }

        componentDidUpdate(preProps, preState, snapshot){
            //组件更新之后的高度
          let newHeight = this.refs.list.scrollHeight
          // scrollTop 需要改变的值
          let finalHeight = newHeight - snapshot.oldHeight
          console.log('finalHeight', finalHeight)
          // 设置滚动条高度
          this.refs.list.scrollTop += finalHeight
        }
        render() {
          const {newsList} = this.state
          return (
            <div className="list" ref='list'>
              {
                newsList.map((item, index)=>{
                  return<div key={index}>{item}</div>
                })
              }
            </div>
          );
        }
      }

      ReactDOM.render(<NewsList count={100}/>, document.getElementById('test'))
    </script>
</body>
</html>

总结

  1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
    1. constructor()
    2. getDerivedStateFromProps()
    3. render()
    4. componentDidMount()
  2. 更新阶段: 由组件内部this.setSate()或父组件render触发
    1. getDerivedStateFromProps
    2. shouldComponentUpdate()
    3. render()
    4. getSnapshotBeforeUpdate()
    5. componentDidUpdate()
  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    1. componentWillUnmount() 重要的钩子:
  4. render:初始化渲染或更新渲染调⽤
  5. componentDidMount:开启监听, 发送ajax请求
  6. componentWillUnmount:做⼀些收尾⼯作, 如: 清理定时器 即将废弃的勾⼦
  7. componentWillMount
  8. componentWillReceiveProps
  9. componentWillUpdate 现在使⽤会出现警告,下⼀个⼤版本需要加上UNSAFE_前缀才能使⽤,以后可能会被彻底废弃,不建议使⽤。