react16.8 新的生命周期getDerivedStateFromProps和 getSnapshotBeforeUpdate 用法

前言:React 16.8 更新了一些新的生命周期,增加了hooks无状态组件,原有的class类组件的生命周期也进行了更新优化

我认为hooks才是React想做的事,React不想废弃原来的类组件,同时想扶正hooks,做了一些兼容,写法上的区别,但是最终结果是一样的,

下面我们来讨论一下新增加的生命周期:

1、getDerivedStateFromProps(props,state)

  • 相当于componentwillmount 和 componentWillReceiveProps合并
  • 主要是应用在于封装组件时调用,组件的state取决于props变化,
  • 无条件的根据 props来更新内部 state,也就是只要有传入 props值, 就更新 state
  • 只有 props 值和 state值不同时才更新 state 值。

我们自己查看会发现这不就是和React.useEffect(()=>{},[]),中的依赖参数同等效果,我们在封装组件时可以用到,具体看代码

类组件:

class List extends React.Component {
   state = {
      list: []
   }
   static getDerivedStateFromProps(props, state) {
      if(props.list !== state.list){
         return {
            list: props.list
         }
      }
      return null;
   }
   render() {
        .... // 展示 list
   }
}

函数组件:

// 函数组件
const List  = React.memo((props) =>{
   const [list,setList] = React.useState([]);

   React.useEffect(()=>{
      setList(props.list);
   }, [props.list]);

   return (
      .... // 展示 list
   )

});

2、getSnapshotBeforeUpdate(prevProps,prevState)

  • 替换componentWillUpdate函数,将参数返回并传递给componentDidUpdate周期函数
  • getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()
  • 此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。
class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 我们是否在 list 中添加新的 items ?
    // 捕获滚动​​位置以便我们稍后调整滚动位置。
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
    // 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
    //(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

继续完善。。。