生命周期函数(旧)

  1. 初始化阶段: 由ReactDOM.render()触发—-初次渲染
    1. constructor()
    2. componentWillMount()
    3. render()
    4. componentDidMount() =====> 常用
      一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
  1. 更新阶段: 由组件内部this.setSate()或父组件render触发
    1. componentWillReceiveProps - props发生改变才会触发 只有组件内部state修改不会触发
    2. shouldComponentUpdate() - 组件是否应该被更新 return true/false
    3. componentWillUpdate()
    4. render() =====> 必须使用的一个
    5. componentDidUpdate()
  1. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

    1. componentWillUnmount() =====> 常用
      一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息


    生命周期函数 - 图1

    生命周期函数(新)v16.2

  2. 初始化阶段: 由ReactDOM.render()触发—-初次渲染

    1. constructor() - 初始化state [ 只执行一次 ]
    2. getDerivedStateFromProps - 初始化执行[一次] 后续更新(包括自身状态更新以及父传子)[N次]
    3. render() - 每次组件渲染触发N次
    4. componentDidMount() =====> 常用 成功render并渲染真实Dom[一次]
      一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
  1. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

    1. getDerivedStateFromProps - 初始化执行[一次] 后续更新(包括自身状态更新以及父传子)[N次]
    2. shouldComponentUpdate() - 组件是否应该被更新,返回false组件render调用
    3. render()
    4. getSnapshotBeforeUpdate
    5. componentDidUpdate() - 组件(Dom)更新后[N次],这里调用setData会导致递归更新,应给setData做if判断 ```javascript // scu 性能优化函数 shouldComponentUpdate(nextProps,nextState){ // return true; //应该更新 //return false;; //阻止更新 // this.state 老的状态 // nextState 新的状态 if(JSON.stringify(this.state)!== JSON.stringify(nextState)){ return true }

    return false }

//根据父组件传入props决定一些逻辑 componentDidUpdate(prevProps,prevState) { // 做法:比较更新前后的props是否相同,来决定是否重新渲染组件 console.log(‘上一次的props:’, prevProps, ‘, 当前的props:’, this.props) if (prevProps.count !== this.props.count) { // this.setState({}) } }

  1. 3. 卸载组件: ReactDOM.unmountComponentAtNode()触发
  2. 1. componentWillUnmount() =====> 常用<br />一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
  3. ```javascript
  4. componentWillUnmount(){
  5. console.log("componentWillUnmount")
  6. window.onresize = null
  7. clearInterval(this.timer)
  8. }

react生命周期(新).png

即将废弃的勾子

  1. componentWillMount -组件即将挂载[一次] render之后最后一次修改state的机会。

    • 原因: 在ssr中 这个方法将会被多次调用, 所以会重复触发多遍,同时在这里如果绑定事件, 将无法解绑,导致内存泄漏 , 变得不够安全高效逐步废弃。
    • getDerivedStateFromProps可代替该函数 因为会初始化执行一次
  2. componentWillReceiveProps - [N次]

    • 原因: 外部组件多次频繁更新传入多次不同的 props,会导致不必要的异步请求 .
    • getDerivedStateFromProps可代替该函数 因为每次更新(包括自身状态更新以及父传子)都会执行 ```javascript componentWillReceiveProps(nextProps){ console.log(“componentWillReceiveProps”,nextProps)

    // 最先获得父组件传来的属性, 可以利用属性进行ajax或者逻辑处理。 … // 把属性转化成孩子自己的状态。 this.setState({ title:nextProps.text+”kerwin” }) } ```

  3. componentWillUpdate - 不能修改props和state[N次],

    • 原因:更新前记录 DOM 状态, 可能会做一些处理,与componentDidUpdate相隔时间如果过 长, 会导致 状态不太信
    • getSnapshotBeforeUpdate可代替该函数 ,触发时间为update发生的时候,在render之后 dom渲染之前返回一个值,作为componentDidUpdate的第三个参数。
  4. 现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。(UNSAFE_componentWillMount)

    getDerivedStateFromProps

    第一次的初始化组件以及后续的更新过程中(包括自身状态更新以及父传子) , 返回一个对象作为新的state,返回null则说明不需要在这里更新state

使用场景:

  1. 若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps

注意:

  1. 必须写static
  2. 必须有return,return的跟state中某个属性一样 则无论怎么修改都是return 的值 ```javascript //做一个根据父组件props.type决定获取数据的案例 state = { list:[],//用于渲染的列表 type:1 //决定list渲染数据的flag }

static getDerivedStateFromProps(props,state){ //拿到的是最新的props和state console.log(‘getDerivedStateFromProps’,props,state); return { type:nextProps.type //修改state.type为props决定的type } }

componentDidUpdate(prevProps,prevState){ if(this.state.type===prevState.type){ return } //根据state.type(由getDerivedStateFromProps提供)获取数据 if(this.state.type===1){ axios() }else{ axios() } }

<a name="heayX"></a>
### getSnapshotBeforeUpdate
>  取代了 componetWillUpdate ,触发时间为update发生的时候,在render之后 dom渲染之前返回一个值,作为componentDidUpdate的第三个参数。  

**使用场景:**

1. 不断获取新闻 界面一直定位在滚动条位置
```jsx
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
      <title>4_getSnapShotBeforeUpdate的使用场景</title>
      <style>
        .list{
          width: 200px;
          height: 150px;
          background-color: skyblue;
          overflow: auto;
        }
        .news{
          height: 30px;
        }
      </style>
      </head>
    <body>
      <!-- 准备好一个“容器” -->
      <div id="test"></div>

      <!-- 引入react核心库 -->
      <script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
      <!-- 引入react-dom,用于支持react操作DOM -->
      <script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
      <!-- 引入babel,用于将jsx转为js -->
      <script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

      <script type="text/babel">
        class NewsList extends React.Component{

          state = {newsArr:[]}

          componentDidMount(){
            setInterval(() => {
              //获取原状态
              const {newsArr} = this.state
              //模拟一条新闻
              const news = '新闻'+ (newsArr.length+1)
              //更新状态
              this.setState({newsArr:[news,...newsArr]})
            }, 1000);
          }

          getSnapshotBeforeUpdate(){
            return this.refs.list.scrollHeight
          }

          componentDidUpdate(preProps,preState,height){
            this.refs.list.scrollTop += this.refs.list.scrollHeight - height
          }

          render(){
            return(
              <div className="list" ref="list">
                {
                  this.state.newsArr.map((n,index)=>{
                    return <div key={index} className="news">{n}</div>
                  })
                }
              </div>
            )
          }
        }
        ReactDOM.render(<NewsList/>,document.getElementById('test'))
      </script>
    </body>
</html>