1 React生命周期

1 React生命周期

只有 class 组件才有生命周期,因为 class 组件会创建对应的实例,而函数组件不会。组件实例从被创建到被销毁的过程称为组件的生命周期

组件的生命周期可分成三个状态:

  • **Mounting(挂载):**第一次把组件渲染到DOM树的过程

  • **Updating(更新):**当组件重新渲染

  • **Unmounting(卸载):**从DOM树中删除

    img

图片来自菜鸟教程

1.1 Mounting过程

  • constructor(): 在 React 组件挂载之前,会调用它的构造函数。
  • getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
  • render(): render() 方法是 class 组件中唯一必须实现的方法。因为React组件的父类React.Component类对除render之外的生命周期函数都有默认实现。它不做实际的渲染只是返回一个JSX描述的结构,实际的渲染是由React来操作渲染的过程。
  • componentWillMount(): 这个 函数会在render函数之前被调用。(既可以在浏览器端运行,也可以在服务端运行)
  • componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。(只在浏览器端运行)

1.2 Mouting过程

componentWillReceiveProps在React新的生命周期中被取消,这个生命周期函数是为了替代componentWillReceiveProps,所以在需要使用componentWillReceiveProps的时候,就可以考虑使用getDerivedStateFromProps来进行替代了。所以这里引用菜鸟教程上的介绍。

每当组件的 state 或 props 发生变化时,组件就会更新。

当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:

  • getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。也就是当props数据某个值发生变化时对state进行赋值。

  • shouldComponentUpdate():当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。

    当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方法。

    此方法仅作为**性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。你应该考虑使用内置的 PureComponent 组件**,而不是手动编写 shouldComponentUpdate()PureComponent 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。

    如果你一定要手动编写此函数,可以将 this.propsnextProps 以及 this.statenextState 进行比较,并返回 false 以告知 React 可以跳过更新。请注意,返回 false 并不会阻止子组件在 state 更改时重新渲染。

    我们不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。

  • render(): render() 方法是 class 组件中唯一必须实现的方法。

  • getSnapshotBeforeUpdate(): 在最近一次渲染输出(提交到 DOM 节点)之前调用。

  • componentDidUpdate(): 在更新后会被立即调用。

render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

1.3 Unmounting过程

componentWillUnmount(): 在组件卸载及销毁之前直接调用

和装载过程与更新过程不一样,这个函数没有配对的 Did 函数,就1个函数,因为 卸载完就完了,没有“卸载完再做的事情”

componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

componentWillUnmount()不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

1.4 生命周期测试

直接使用create-app脚手架创建一个react基础项目

为了方便测试,需要提前移除index.js下的严格模式。

在 React 的严格模式 (<React.StrictMode>) 下,某些生命周期方法会被调用两次。这是为了帮助开发者发现副作用和潜在的问题。具体来说,以下生命周期方法会被调用两次:

constructor

render

componentDidMount

componentDidUpdate

这不会影响生产环境,只会在开发环境中启用。

如果你想避免这种行为,可以暂时移除严格模式:

1.4.1一个可以挂载和卸载的时钟

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  //<React.StrictMode> 严格模式下,React 会执行两次组件的 render 方法,以帮助发现潜在的副作用
    <App />
  //</React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Clock.js

import React from 'react';

class Clock extends React.Component {
    constructor(props) {
      super(props);
      this.state = {date: new Date()};
    }
   
    componentDidMount() { // 组件挂载时执行
      this.timerID = setInterval(
        () => this.tick(),
        1000
      );
      console.log('组件挂载时执行');
    }
   
    componentWillUnmount() { // 组件卸载时执行
      clearInterval(this.timerID);
      console.log('组件卸载时执行');
    }
   
    tick() { // 每秒执行一次
      this.setState({
        date: new Date()
      });
    }
   
    render() {
      return (
        <div>
          <h2>It is {new Date().toLocaleTimeString()}.</h2>
        </div>
      );
    }
  }

  export default Clock;

App.js 这里面有一个button 可以加载Clock组件和卸载Clock组件

import React, { useState } from 'react';
import logo from './logo.svg';
import './App.css';
import Clock from './Clock';

function App() {
  const [showClock, setShowClock] = useState(true);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        {showClock && <Clock />}
        <button onClick={() => setShowClock(!showClock)}>
          {showClock ? '卸载 Clock 组件' : '加载 Clock 组件'}
        </button>
      </header>
    </div>
  );
}

export default App;

先挂载点击卸载后卸载

image-20240827101343177

image-20240827101420949

1.4.2 一个可以更新的按钮

Button,jsx

import React, { Component } from 'react';

class Button extends Component {
    constructor(props) {
      super(props);
      this.state = { data: 0 };
      this.setNewNumber = this.setNewNumber.bind(this);
    }
   
    setNewNumber() {
      this.setState({ data: this.state.data + 1 });
    }
   
    render() {
      return (
        <div>
          <button onClick={this.setNewNumber}>INCREMENT</button>
          <Content myNumber={this.state.data} />
        </div>
      );
    }
  }
   
  class Content extends React.Component {
    componentDidMount() {
      console.log("Component DID MOUNT!");
    }
   
    shouldComponentUpdate(newProps, newState) {
      return true;
    }
   
    componentDidUpdate(prevProps, prevState) {
      console.log("Component DID UPDATE!");
    }
   
    componentWillUnmount() {
      console.log("Component WILL UNMOUNT!");
    }
   
    render() {
      return (
        <div>
          <h3>{this.props.myNumber}</h3>
        </div>
      );
    }
  }


  export default Button;

App.js

import React, { useState } from 'react';
import logo from './logo.svg';
import './App.css';
import Button from './Button';

function App() {
  const [showButton, setShowButton] = useState(true);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>

        {showButton && <Button />}
        <button onClick={() => setShowButton(!showButton)}>
          {showButton ? '卸载 Button 组件' : '加载 Button 组件'}
        </button>
      </header>
    </div>
  );
}

export default App;

先挂载点击按钮后更新,点击卸载后卸载

image-20240827102620043

image-20240827102646244

参考

react.js - React新生命周期getDerivedStateFromProps的理解与使用 - 个人文章 - SegmentFault 思否

React.Component – React (reactjs.org)

React 组件生命周期 | 菜鸟教程 (runoob.com)

react.js - React生命周期深度完全解读 - 个人文章 - SegmentFault 思否

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜业

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值