React原理 - React New Component Lifecycle

目录

扩展学习资料

React New Component Lifecycle【新生命周期】

React 组件新生命周期详解

React组件老生命周期 v15.x

为什么Fiber Reconciler要有新的生命周期函数呢?

新的组件生命周期

getDerivedStateFromProps

挂载阶段

更新阶段

卸载阶段

异常捕获

新版组件升级

升级组件版本

APP.js

component.js

升级组件遍布-保留选项


扩展学习资料

名称

链接

React 组件

React.Component – React

React v16.3 组件生命周期

关于React v16.3 新生命周期 - 掘金

React 组件图

React lifecycle methods diagram

React New Component Lifecycle【新生命周期】

掌握新的组件生命周期,在老的生命周期组件中进行更新代码。

React 组件新生命周期详解

React组件老生命周期 v15.x

  1. Initialization【初始化】:state的初始化;及props是否转化为state;setup;
  2. Mounting【挂载过程】:componentWillMount()【新版删除1】->render()->componentDidMount()
  3. Updation【业务更新】:(props【父级传递的props更新;被动更新】)=>componentWillReceiveProps()【新版删除2】->shouldcomponentUpdate(){return true}-> componentWillUpdate()【新版删除3】->render()->componentDidUpdate();(states【主动调用setState更新】)=>shouldcomponentUpdate(){return true}-> componentWillUpdate()【新版删除3】->render()->componentDidUpdate()
  4. Unmounting【卸载过程】:componentWillUnmount

为什么Fiber Reconciler要有新的生命周期函数呢?

答:1.Fiber Reconciler中为了在没有更新前再次混入更新任务导致Fiber更新整个流程有点混乱;为了适配Fiber Reconciler就取消了在更新前可以再次触发更新的操作。

(有部分同学会在componentWillMount中setState;异步请求)

Fiber Reconciler要求对组件的生命周期,至少在更新前做到要纯函数行为。【不能写入异步的操作,影响更新流程】

2.我们之前并不是Fiber Reconciler中导致的,在刚开始接触React的时候会有大部分同学,会在componentWillMount进行set相关操作(setState,进行初始化redux操作,以及调用接口异步操作)【应该写在构造函数constructor中】,不然会多进行一遍vDom diff;

另一个就是componentWillUpdate中进行setState操作【不带任何条件的操作】,相当于触发了一个无线循环。

总结:基于这两点,一个是我们在老的生命周期中对一些方法的滥用,以及为了适配Fiber Reconciler当中更新前的一些流程处理,是为了我们后面的异步渲染做准备,所以React16.x之后就更新了新的生命周期函数。

 

新的组件生命周期

React v16.3版本

static getDerivedStateFromProps(props, state)【替换componentWillReceiveProps】、static getSnapshotBeforeUpdate【静态方法,静态方法中不能调用this】

1.挂载时:constructor()【构造函数】->getDerivedStateFromProps()【新增1】->render()->React更新DOM和refs->componentDidMount()

2.更新时:New Props触发更新 =>getDerivedStateFromProps()【新增1】->shouldComponentUpdate(){return true}->render()->getSnapshotBeforeUpdate()【新增2】->React更新DOM和refs->componentDidUpdate()

setState()触发更新=>shouldComponentUpdate(){return true}->render()->getSnapshotBeforeUpdate()【新增2】->React更新DOM和refs->componentDidUpdate()

forceUpdate()触发更新=>render()->getSnapshotBeforeUpdate()【新增2】->React更新DOM和refs->componentDidUpdate()

3.卸载时:componentWillUnmount()

Rebder(更新)阶段【render()方法之前】”:纯净【纯函数】且不包含副作用【重新触发setState、异步请求、redux更新】。可能会被React暂停,中止或重新启动。

Pre-commit阶段”:可以读取DOM

Commit阶段”:可以使用DOM,运行副作用,安排更新。

React v16.4版本【通常用的v16.4版本】

与v13比

挂载阶段【constructor】和更新阶段【New Props,setState(),forceUpdate()】之后都会触发getDerivedStateFromProps()

getDerivedStateFromProps

是一个派生state,所有可能触发state变更的都会经过这个静态方法,主要是返回一个派生类的state

 

挂载阶段

挂载阶段的函数

  • constructor 构造函数,初始化state,以及为事件处理函数绑定实例。【初始化数据】
  • getDerivedStateFromProps (nextProps, state) { this === window } 新增的静态方法。返回一个新的state,或者是null(后续不更新)。
  • render 渲染函数。
  • componentDidMount 挂载成功后立即调用的函数。【副作用操作,调用fetch(接口数据),绑定真实dom数据,如window.onresize,window.onscroll事件等】

更新阶段

更新阶段的函数

  • getDerivedStateFromProps props变化或者state方法触发。
  • shouldComponentUpdate 判断是否进行更新。【可以对UI更新逻辑进行优化】
  • render 渲染函数。
  • getSnapshotBeforeUpdate render方法之后调用,返回一个dom更改之前的快照,将配合后续的componentDidUpdate方法使用。
  • componentDidUpdate(oldprops, oldstate) 更新后会被立即调用。如果设置了getSnapshotBeforeUpdate(),会多出一个componentDidUpdate(oldprops, oldstatesnapshot);异步,进行setState操作,要进行条件判断,避免死循环更新,

卸载阶段

卸载阶段的函数

  • componentWillUnmount 卸载函数,组件卸载及销毁之前直接调用。主要用于清除一些在组件生命周期订阅,真实DOM事件以及setTimeout/setInterval的返回值。【不做的话,可能会引起内存泄漏、溢出】

异常捕获

v16.x 异常捕获的函数【全局错误处理,后代组件异常处理】

  • componentDidCatch(error,info) 生命周期方法在后代组件抛出错误后被调用。方法接收两个参数(error,info),分别是错误信息和错误组件的栈信息。;做一些错误日志上传,错误信息,错误源。不推荐在这里修改state,处理UI页面展示。避免setState影响Fiber 协调
  • getDerivedStateFromError(error) 在后代组件抛出错误后调用,接收一个参数(error)表示具体错误信息。做一些兼容错误页面,返回一些对象,控制页面元素,用户体验更好,是否出现不可抗性错误。新增的静态类型,返回一个派生类的state,建议在这里修改state进行页面处理

v15.x之前的处理方案

1.关键代码加try{}catch(e){}包裹

2.监听window.onerror方案。也可以通过window.addEventListener("error", function(evt){})

3.react 提供的一个内置捕获错误方法:unstable_handleError;没有正式对外宣布过,并不是一个标准的稳定的方法

新版组件升级

升级组件版本

  • componentWillMount
    • render方法之前调用,在此调用setState并不会触发再次渲染。
    • 通常会在这个方法中进行页面标题的一些修改以及其他与再次render不相关的操作。
  • UNSAFE_componentWillMount(不推荐用这个替换componentWillMount)
    • 与state相关的操作挪到constructor方法中执行。
    • 异步操作挪到componentDidMount中执行。
  • componentWillUpdate
    • 在组件收到新的props或者state时,会在渲染之前调用。
    • 方法内不能调用setState,触发循环,内存泄漏。
  • UNSAFE_componentWillUpdate(官方保留方法,不推荐使用)
    • 应该在shouldComponentUpdate中判断是否更新。
  • componentWillReceiveProps
    • 接收父级组件传递过来最新的props,转化为组件内的state。
    • 判断是否进行更新或者执行异步请求数据。
  • UNSAFE_componentWillReceiveProps(官方保留方法,不推荐使用)
    • 与渲染相关的props直接渲染,不需要处理为组件内state。
    • 异步数据请求在componentDidUpdate中处理。
    • getDerivedStateFromProps方法替换,需要考虑生命周期的执行顺序。【挂载阶段【constructor】和更新阶段【New Props,setState(),forceUpdate()】之后都会触发getDerivedStateFromProps()

APP.js

import React, { Component } from "react";
import NewCycle from "./component";
import "./styles.css";
const mockList = [
  {
    key: 1,
    text: "这是列表项-1"
  },
  {
    key: 2,
    text: "这是列表项-2"
  },
  {
    key: 3,
    text: "这是列表项-3"
  },
  {
    key: 4,
    text: "这是列表项-4"
  }
];
export default class App extends Component {
  // let cycleList = [];
  state = {
    cycleList: []
  };
  // const [cycleList, setCycleList] = useState([]);
  queryList = () => {
    this.setState({
      cycleList: mockList
    });
  };
  render() {
    return (
      <div className="App">
        <NewCycle
          cycleList={this.state.cycleList}
          queryListCB={this.queryList}
        />
      </div>
    );
  }
}

component.js

import React, { Component } from "react";
import shallowequal from "shallowequal";// 开源第三方库,shallowequal比较值相等,或者对象含有相同的属性、且属性值相等
export default class NewCycle extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [],
      parentList: []
    };
  }
  /* 
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (!shallowequal(this.props, nextProps)) {
      const { cycleList } = nextProps;
      this.setState({
        list: cycleList.map(item => ({
          ...item,
          label: "origin" // 组件内部要调用一些逻辑
        }))
      });
    }
  } 
  
  componentDidUpdate(prevProps, prevState) {
    // console.log(prevProps, prevState, this.props, this.state);
    // 比getDerivedStateFromProps晚一些,更新完成之后才触发
    if (!shallowequal(this.props, prevProps)) {
      const { cycleList } = this.props;
      this.setState({
        list: cycleList.map((item) => ({
          ...item,
          label: "标题"
        }))
      });
    }
  }
  */
  static getDerivedStateFromProps(props, state) {// newprops,oldstate
    // 触发时机有4种,要做好兼容判断
    const { cycleList } = props;
    const { parentList } = state;
    /**
     * prueComponent 在这里如果返回有数据的对象,
     * shouldComponentUpdate 会返回true
     * 最好是不要再用state来控制
     */
    //  初始化不执行         &&
    if (cycleList.length > 0 && !shallowequal(cycleList, parentList)) {
      return {
        list: cycleList.map((item) => ({
          ...item,
          label: "标题"
        })),
        parentList: cycleList
      };
    }
    return null;
  }
  
  queryList = () => {
    const { queryListCB } = this.props;
    if (typeof queryListCB === "function") {
      queryListCB();
    }
  };
  render() {
    const { list } = this.state;
    return (
      <div>
        {list.map(item => (
          <div key={item.key}>
            {item.label}-{item.text}
          </div>
        ))}
        <button onClick={this.queryList}>按钮</button>
      </div>
    );
  }
}

升级组件遍布-保留选项

老工程代码量很多,改动特别麻烦。需要回归的点非常多!怎么解决?

npx react-codemod rename-unsafe-lifecycles 
// 此方法会给需要添加'UNSAFE_'的方法加上它。 此时版本为【v16.x】 (v15.x < v16.x < v17)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值