React --生命起源(新生命周期)

生命周期分解图

在这里插入图片描述
在这里插入图片描述

一、新增生命周期

1.1 static getDerivedStateFromProps(nextProps, state)

  该生命周期任何时候, state 的值都取决于 props ( Derived 意思为衍生的,英语好的同学看到名字就能知道这个生命周期的用法了吧)

static getDerivedStateFromProps(nextProps, state) {
	return null;
}

  此生命周期执行的时机在第一次初始化后,父组件重新渲染后,或者调用 setState() / forceUpdate() 后。该方法属于静态方法,无权访问 class 内部,也就是拿不到 this ,但是该回调函数的 return 返回值,将作为 state 与 组件内部 state 进行合并,若返回 null 则不更新 state

  注意:

  1. react@16.3 版本下 setState() forceUpdate() 并不会进入该钩子函数。

  2.这是一个非常规的生命周期,因为会派生新的state,导致数据来源多样,难以维护,应该考虑使用受控组件或者完全非受控组件来代替。

1.2 getSnapshotBeforeUpdate(prevProps, prevState)

  同理,英语好的同学看到标题应该就能明白用法了, Snapshot 意思为快照。具体用发需要配合 componentDidUpdate 一块使用。

getSnapshotBeforeUpdate() {
	return 1;
}
componentDidUpdate(prevProps, prevState, snapshot) {

}

  在真实 dom ref 确认更新前进入该钩子函数,能在发生更改前从之前的 DOM 中获取一些信息,类似于上一次的 Dom 快照,返回值将作为参数传递给 componentDidUpdate , 常用于获取滚动位置等。

二、修改

   componentDidUpdate(prevProps, prevState, snapshot )

  新增第三个参数接收来自 getSnapshotBeforeUpdate 的返回值。

三、计划删除/即将过时

   componentWillMount / componentWillUpdate / componentWillReceiveProps

  UNSAFE_componentWillMount

  UNSAFE_componentWillUpdate

  UNSAFE_componentWillReceiveProps

废弃原因

  同步渲染过渡到异步渲染( React Fiber

  到目前为止, React 的渲染更新过程都是同步的,每一次加载或者更新树组件,都会做很多事,比如调用各个组件的生命周期,计算对于 Virtual Dom 最后更新 DOM 树,然而过多的操作,更深的层级容易导致这系列的执行时间过长,浏览器的主线程长期被占用,从而出现卡顿或者假死的现象。同步渲染过程如下:

  1. 首次渲染: willMount > render > didMount
  2. props 更新时: receiveProps > shouldUpdate > willUpdate > render > didUpdate
  3. state 更新时: shouldUpdate > willUpdate > render > didUpdate
  4. 卸载时: willUnmount

  为了解决同步操作时间过长的方法, React 计划在 17 版本启用最新的核心算法: React Fiber 从而实现异步渲染——大致原理是将一次更新过程变成多个分片完成,主要就是分为 Reconciliation Phase (协调:找出需要变动的节点)和 Commit Phase (提交更新)。

协调阶段

   React 会霸占着浏览器资源,导致用户触发的时间得不到响应以及掉帧,因此 Fiber 将协调阶段按照优先级分段执行,任何低优先级的更新都可能被打断重来。

  计划删除/即将过时的生命周期就发生在 render 前的协调阶段,因此随时可能会被打断重新执行,这些钩子函数就会变得不可预测。

四、旧生命周期替换方案

4.1 componentWillMount

  a:初始化 state :转移至 constructor this.state 内。

  b:不建议在该生命周期内有副作用操作,如若有也可以转移至 componentDidMount

4.2 componentWillReceiveProps

  a:副作用操作(比如数据请求/动画):转移至 componentDidUpdate

  b:考虑受控组件和完全非受控组件。

  c:实在不行也可以使用 getDerivedStateFromProps,但务必做好条件判断。

componentWillReceiveProps
// before
componentWillReceiveProps(nextProps) {	
  if (nextProps.translateX !== this.props.translateX) {
    this.setState({	
      translateX: nextProps.translateX,	
    });	
  }	
}

// after
static getDerivedStateFromProps(nextProps, prevState) {
  if (nextProps.translateX !== prevState.translateX) {
    return {
      translateX: nextProps.translateX,
    };
  }
  return null;
}

   getDerivedStateFromProps 中禁止了组件去访问 this.props ,强制开发者去比较 nextProps prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state ,而不是去做其他一些让组件自身状态变得更加不可预测的事情。

   React 团队试图通过框架级别的 API 来约束或者说帮助开发者写出可维护性更佳的 JavaScript 代码。

// before
componentWillReceiveProps(nextProps) {
  if (nextProps.isLogin !== this.props.isLogin) {
    this.setState({	
      isLogin: nextProps.isLogin,	
    });
  }
  if (nextProps.isLogin) {
    this.handleClose();
  }
}
// after
static getDerivedStateFromProps(nextProps, prevState) {
  if (nextProps.isLogin !== prevState.isLogin) {
    return {
      isLogin: nextProps.isLogin,
    };
  }
  return null;
}

componentDidUpdate(prevProps, prevState) {
  if (!prevState.isLogin && this.props.isLogin) {
    this.handleClose();
  }
}

4.3 componentWillUpdate

  通常可以替换成 componentDidUpdate() getSnapshotBeforeUpdate()

componentWillUpdate
class ScrollingList extends React.Component {
  listRef = null;

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // Are we adding new items to the list?
    // Capture the scroll position so we can adjust scroll later.
    if (prevProps.list.length < this.props.list.length) {
      return (
        this.listRef.scrollHeight - this.listRef.scrollTop
      );
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // If we have a snapshot value, we've just added new items.
    // Adjust scroll so these new items don't push the old ones out of view.
    // (snapshot here is the value returned from getSnapshotBeforeUpdate)
    if (snapshot !== null) {
      this.listRef.scrollTop =
        this.listRef.scrollHeight - snapshot;
    }
  }

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

  setListRef = ref => {
    this.listRef = ref;
  };




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值