【详解】 React 组件生命周期 API 及 useEffect Hook 新特性方案

本文详细介绍了React组件的生命周期,包括挂载、更新和卸载阶段的API,强调了如何使用`useEffect` Hook来替代传统的生命周期方法。在React v16.8版本中,`useEffect`的引入改变了函数组件的游戏规则,允许在函数组件中实现类组件的生命周期功能。文章还提供了一些高质量的React Hooks相关阅读资源。
摘要由CSDN通过智能技术生成


本文篇幅较长,如果你想要:

  1. 完整了解整个组件生命周期的变更和对应函数API,那么请从头开始;
  2. 快速理解传统生命周期函数API的含义和使用,那么点击目录第二部分;
  3. 快速了解如何在函数组件中使用useEffect来替代原有的生命周期API,那么点击目录第三部分。

一、 引言

如果你是一名前端开发者,并且使用React开发框架,那么你一定绕不开React的一个核心概念——组件生命周期。 组件的生命周期描述的是一个组件从创建,渲染,加载,显示到卸载的整个过程。其大致过程如下:
图一 React 组件生命周期图(v16.4)

图片来源请戳此链接:http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

我们从上图可以得知,一个组件主要包括三种行为,分别是:创建,更新,卸载。每个行为又可以划分为:Render 渲染阶段和 Commit 阶段 (更新时存在Pre-Commit 阶段)。这里先简单了解一下生命周期的概况,后文会进行详细描述。

React 官方开发者在生命周期的每个阶段都提供了相关的API,我们可以使用这些API定义组件在某个生命周期进行执行相关的行为。比较常用的就是使用componentDidMount API,在该函数内部获取来自服务器的数据。

学习这些API函数的使用并了解组件的生命周期的运行机制,是一个React开发者的基本功

但是,我们必须不能只注重 API 的使用,而忽略了对生命周期的过程理解,API 只是 API,随时都有可能被替代!

这不,在 React v16.8 版本中,横空出世的 Hooks (俗称钩子)颠覆了之前的类组件范式,让函数组件逐渐成为主流,越来越多的团队开始考虑基于Hooks进行项目的重构,过去那种在类组件中调用各种生命周期API函数的方法将会慢慢成为过去(不过现在还是得学呀…)

本文不打算进行详述Hooks的用法及优越性,已经有许多优秀的前端团队对其展开了极富深度的论述啦,我只是一个刚入门不久的前端菜鸟,暂时难以从高层的视角来评判,如果你感兴趣,本文在第四部分推荐阅读给出一些高质量的链接,你可以学到更多。

回到主题。Hooks 提供了一套新的阐释组件生命周期的方式 ,原先许多生命周期的 API 都有了对应的 Hooks 解决方案——使用强大的useEffect这一Hooks函数

综上,本文主要关注以下内容:

  1. 类组件生命周期理解和API用法;
  2. 如何在函数组件中使用useEffect来替代类组件的生命周期API。

攥写本文的初衷是,本人最近在经常使用React框架开发,对生命周期这一核心概念有必要进行一番梳理,同时也发现网上关于讲解如何使用新特性Hooks来定制生命周期行为的博文数目较少而且不全面,所以我花费几个小时的时间来整理这些概念,总结方法并提供具体的代码实例,希望能帮助到大家,互相学习。


二、 组件生命周期过程及API详解

这里先放我从谷歌搜到的一张大家都在用的生命周期图(图源见链接),直接从API入手描述整个组件的生命周期过程,如果你已经使用过相关的API,那相当明了,但考虑到初学者,我还是基于个人理解给大家归纳总结一下,帮助大家理解、记忆和使用。
组件生命周期API调用流程图
本文将API归为三类:

  1. Mount:挂载API
  2. Update: 更新API
  3. Unmount:卸载API

结合上述流程图,我们从这三类API开始展开叙述,简单讲解一些不常用的API (不完全覆盖),多把文字放在常用的API(基本覆盖)上。

2.1 Mount

挂载一个组件的过程是先实例化创建该组件并渲染,然后读取DOM使得组件运行在浏览器中。整个过程涉及到的 API 函数如下:
在这里插入图片描述
当组件在客户端实例化首次创建时,以下方法依次被调用:

  1. getDefaultProps(ES5语法,过时)
  2. getInitialState(ES5语法,过时)
  3. componentWillMount(弃用)
  4. render(必须使用)
  5. componentDidMount(常用)

当组件属于服务端渲染时,以下方法依次被调用:

  1. getDefaultProps
  2. getInitialState
  3. componentWillMount
  4. render

服务端渲染没有 componentDidMount 方法时因为其执行阶段是组件挂载(插入DOM树)之后,才会执行,发生在客户端。

但需要提醒的是,getDefaultPropsgetInitialState 方法仅适用于非ES6语法情况,在ES6语法中我们使用 constructor函数来代替 getInitialState 函数,而getDefaultProps则可以通过手动赋值指定props属性,但已不属于函数方法了。(来源官方文档不适用ES6),但是考虑到可能还有些人依旧会使用ES5语法,这里也会简单介绍这两个函数。(后续若非特别指明,否则讨论范围都在ES6语法之内)

同时在图一,我们可以得知在constructor之后,render之前会有一个getDerivedStateFromProps函数,这个函数在挂载和更新阶段都有可能调用,我们放在update部分来讲。

所以下文我将介绍上述6个函数,包括函数的作用,方法和一些注意事项。

2.1.1 constructor

这是目前常用的一个函数,我们编写的React 类组件都是React.Component基类的继承,组件进行实例化的时候,都会调用其构造函数;如果你不初始化 state,不绑定方法的话,你不需要为 React 组件实现构造函数(它会调用默认构造函数)。

而且在构造函数的开头,你需要调用 super(props), 不然会有许多蜜汁bug难以定义和识别;

通常构造函数的作用就是:

  1. 初始化内部state变量
  2. 为事件处理函数绑定实例
    需要注意的时,在构造函数里不要出现setState方法,我们仅需要为 this.state 赋初始值即可。

一个常见的例子如下:

// credit to https://react.docschina.org/docs/react-component.html#constructor
constructor(props) {
   
  super(props);
  // 不要在这里调用 this.setState()
  this.state = {
    counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}

2.1.2 getDefaultProps

这种方法其实只有在使用非ES6语法定义组件(即采用ES5语法 React.createClass定义组件)的时候才会出现,这是一种声明默认组件属性(props)的方法。该函数只会调用一次。
一个简单的例子:

// credit to https://www.cnblogs.com/MuYunyun/p/6629096.html#_lab2_0_0
var MyTitle = React.createClass({
   
  getDefaultProps : function () {
   
    return {
   
      title : 'Hello World'  // 声明默认的属性title
    };
  },

  render: function() {
   
     return <h1> {
   this.props.title} </h1>;  // 调用props属性
   }
});

ReactDOM.render(
  <MyTitle />,
  document.body
);

而在ES6语法中,这个函数已经被弃用了,起同样作用的写法如下:

// credit to 
// https://zh-hans.reactjs.org/docs/react-without-es6.html#setting-the-initial-state
class Greeting extends React.Component {
   
  // ...
}

Greeting.defaultProps = {
   
  name: 'Mary'
};

2.1.3 getInitialState

ES5语法中,这个函数的作用相当于初始化每个组件实例的state变量;在ES6语法中,我们可以通过在constructor函数里头对this.state赋初始值,以起到同样的效果。
getInitialStategetDefaultProps的区别在于,getDefauProps 对于组件类来说只会调用一次,而getInitalState是在每个组件实例化的时候都会调用,并且只调用一次。而props和state的区别在于props是通过父组件传递,在所有实例中共享,而state只存在组件内部,保存组件的某些状态。
这里提供一个代码实例帮助理解:

var LikeButton = React.createClass({
   
  getInitialState: function() {
   
    return {
   liked: false};
  },
  handleClick: function(event) {
   
    this.setState({
   liked: !this.state.liked});
  },
  render: function() {
   
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={
   this.handleClick}>
        You {
   text} this. Click to toggle.
      </p>
    );
  }
});
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值