• wordpress CMS主题:ssmay主题 wordpress CMS主题:ssmay主题
  • 首页 > 前端开发 > 关于React v16.3 新生命周期

    关于React v16.3 新生命周期

    作者: 分类:前端开发 点击: 204 次
    wordpress CMS主题:ssmay主题

      扫描下面的二维码,“关注”我的百家号。

      变更的部分

      react v16.3终于出来了,最大的变动莫过于生命周期去掉了以下三个

      • componentWillMount
      • componentWillReceiveProps
      • componentWillUpdate

      同时为了弥补失去上面三个周期的不足又加了两个

      • static getDerivedStateFromProps
      • getSnapshotBeforeUpdate

      当然,这个更替是缓慢的,在整个16版本里都能无障碍的使用旧的三生命周期,但值得注意的是,旧的生命周期(unsafe)不能和新的生命周期同时出现在一个组件,否则会报错“你使用了一个不安全的生命周期”。

      为什么要改

      旧的生命周期十分完整,基本可以捕捉到组件更新的每一个state/props/ref,没有什从逻辑上的毛病。

      但是架不住官方自己搞事情,react打算在17版本推出新的Async Rendering,提出一种可被打断的生命周期,而可以被打断的阶段正是实际dom挂载之前的虚拟dom构建阶段,也就是要被去掉的三个生命周期。

      生命周期一旦被打断,下次恢复的时候又会再跑一次之前的生命周期,因此componentWillMount,componentWillReceiveProps, componentWillUpdate都不能保证只在挂载/拿到props/状态变化的时候刷新一次了,所以这三个方法被标记为不安全。

      两个新生命周期

      static getDerivedStateFromProps

      • 触发时间(v16.4修正):组件每次被rerender的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后。在v16.3版本时,组件state的更新不会触发该生命周期。
      • 每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state.
      • 配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法
      class Example extends React.Component {
        static getDerivedStateFromProps(nextProps, prevState) {
          // 没错,这是一个static
        }
      }
      

      getSnapshotBeforeUpdate

      • 触发时间: update发生的时候,在render之后,在组件dom渲染之前。
      • 返回一个值,作为componentDidUpdate的第三个参数。
      • 配合componentDidUpdate, 可以覆盖componentWillUpdate的所有用法。
      class Example extends React.Component {
        getSnapshotBeforeUpdate(prevProps, prevState) {
          // ...
        }
      }
      

      建议用法总结

      1. 初始化state — Initializing state

        • 在constructor初始化state就可以了
      2. 请求数据 — Fetching external data

        • 在componentDidMount请求异步加载的数据
        • 有一种错觉,在componentWillMount请求的数据在render就能拿到,但其实render在willMount之后几乎是马上就被调用,根本等不到数据回来,同样需要render一次“加载中”的空数据状态,所以在didMount去取数据几乎不会产生影响。
      3. 添加事件监听 — Adding event listeners (or subscriptions)

        • 在componentDidMount中添加加事件监听
        • react只能保证componentDidMount-componentWillUnmount成对出现,componentWillMount可以被打断或调用多次,因此无法保证事件监听能在unmount的时候被成功卸载,可能会引起内存泄露
      4. 根据props更新state — Updating state based on props

        • 用getDerivedStateFromProps(nextProps, prevState), 将传入的props更新到state上
        • 用来代替componentWillReceiveProps(nextProps, nextState),willReceiveProps经常被误用,导致了一些问题,因此该方法将不被推荐使用。
        • getDerivedStateFromProps是一个static方法,意味着拿不到实例的this,所以想要在setState之前比对一下props有没有更新,下面方法是不能用了
         if (this.props.currentRow !== nextProps.currentRow) {
         	...
         }
        

        取而代之的是,额外写一个state来记录上一个props (` ^ ‘)

        if (nextProps.currentRow !== prevState.lastRow) {
          return {
            ...
            lastRow: nextProps.currentRow,
          };
          // 不更新state
          return null
        }
        
        • 为什么我们不给一个prevProps参数呢,官方解释是,一来prevProps第一次被调用的时候是null,每次更新都要判断耗性能,二来如果大家都习惯了,以后react不记录prevProps的话(啥),可以省下不少内存
      5. 触发请求 — Invoking external callbacks

        • 在生命周期中由于state的变化触发请求,在componentDidUpdate中进行
        • 为什么不在componentWillUpdate中的理由同上2
      6. props更新引起的副作用 — Side effects on props change

        • props更改引发的可视变化(副作用,比如log,ga),在componentDidUpdate中处理
        // 在didUpdate中根据props更新的确很不适应
        // props变了也是可以触发update的
        componentDidUpdate(prevProps, prevState) {
        	if (this.props.isVisible !== prevProps.isVisible) {
        	  logVisibleChange(this.props.isVisible);
        	}
        }
        
        • componentWillUpdate, componentWillReceiveProps在一次更新中可能会被触发多次,因此这种只希望触发一次的副作用应该放在保证只触发一次的componentDidUpdate中。
      7. props更新时重新请求 — Fetching external data when props change

        • 传入新的props时重新异步取数据,getDerivedStateFromProps+ componentDidUpdate 替代 componentWillReceiveProps
        // old
          componentWillReceiveProps(nextProps) {
            if (nextProps.id !== this.props.id) {
            	this.setState({externalData: null});
              this._loadAsyncData(nextProps.id);
            }
          }
        
        // new
          static getDerivedStateFromProps(nextProps, prevState) {
            // Store prevId in state so we can compare when props change.
            if (nextProps.id !== prevState.prevId) {
              return {
                externalData: null,
                prevId: nextProps.id,
              };
            }
            // No state update necessary
            return null;
          }
          componentDidUpdate(prevProps, prevState) {
            if (this.state.externalData === null) {
              this._loadAsyncData(this.props.id);
            }
          }
        
      8. 在更新前记录原来的dom节点属性 — Reading DOM properties before an update

        • 在upate之前获取dom节点,getSnapshotBeforeUpdate(prevProps, prevState)代替componentWillUpdate(nextProps, nextState)
        • getSnapshotBeforeUpdate在render之后,但在节点挂载前
        • componentDidUpdate(prevProps, prevState, snapshot)直接获得getSnapshotBeforeUpdate返回的dom属性值

      生命周期功能替换一览

        static getDerivedStateFromProps(nextProps, prevState) {
          4. Updating state based on props
          7. Fetching external data when props change
        }
        constructor() {
      	1. Initializing state
        }
        componentWillMount() {
        	// 1. Initializing state
        	// 2. Fetching external data
        	// 3. Adding event listeners (or subscriptions)
        }
        componentDidMount() {
      	2. Fetching external data
      	3. Adding event listeners (or subscriptions)
        }
        componentWillReceiveProps() {
        	// 4. Updating state based on props
        	// 6. Side effects on props change
        	// 7. Fetching external data when props change
        }
        shouldComponentUpdate() {
        }
        componentWillUpdate(nextProps, nextState) {
        	// 5. Invoking external callbacks
        	// 8. Reading DOM properties before an update
        	
        }
        render() {
        }
        getSnapshotBeforeUpdate(prevProps, prevState) {
      	8. Reading DOM properties before an update
        }
        componentDidUpdate(prevProps, prevState, snapshot) {
      	5. Invoking external callbacks
      	6. Side effects on props change
        }
        
        componentWillUnmount() {
        }
      
      

      最后

      上面的内容基本就是结合我的一些经验半翻译半总结,有不准确的地方欢迎指正。

      对更多细节感兴趣的话可以去看官方文档,https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html

      对async-rendering或者对dan小哥哥感兴趣的话可以去看看他在前端大会上的一段小演示:https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html

      本文转载于:猿2048https://www.mk2048.com/blog/blog_hj1kbihjkj.html



      欢迎“关注”我的百家号。

      头条二维码
      加入我的QQ群
      头条二维码
      关注我的百家号

    文章作者:sunny
    本文地址:http://wanlimm.com/77202006218453.html
    版权所有 © 转载时必须以链接形式注明作者和原始出处!

    上一篇:
    下一篇:
    wordpress CMS主题:ssmay主题

    或许你会感兴趣的文章:

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注

    This site uses Akismet to reduce spam. Learn how your comment data is processed.