likes
comments
collection
share

一看就懂的React生命周期

作者站长头像
站长
· 阅读数 72

一看就懂的React生命周期

简介

React生命周期是一个不断演进的概念,特别是在16.3版本后。这一演进包括了弃用某些生命周期钩子并引入全新的钩子函数。在本文中,我们将会从以下四点开始讲解:

  1. 新旧生命周期对比--图解
  2. 旧的生命周期
  3. 新的生命周期
  4. 总结

新旧生命周期对比

什么是生命周期:react实例从创建到销毁的过程,就是生命周期。一般来说,生命周期分为创建、挂载、更新、卸载四个阶段。 从旧生命周期入手,由旧到新,把旧的看懂了,理解新的也就事半功倍,废话不多说,看下图(图片均来自网络)

旧的:

一看就懂的React生命周期

新的:

一看就懂的React生命周期

通过对比不难发现,新的生命周期中不再使用以下三个钩子函数componentWillMount()componentWillReceiveProps(nextProps)componentWillUpdate(nextProps, nextState)

为何不再使用

1、componentWillMount()

不推荐使用的原因主要是它的执行时机可能会导致一些问题。具体来说,如果你在componentWillMount() 中触发了异步操作,可能会导致在组件卸载前仍然执行未完成的操作,这可能会引发潜在的错误。

2、componentWillReceiveProps(nextProps)

这个生命周期方法被不推荐使用,因为它容易导致状态不一致的问题。在这个方法中,你可以在组件接收新的props之前执行某些操作,但它不适合进行依赖于props的状态更新。

3、componentWillReceiveProps(nextProps)

componentWillReceiveProps()类似,这个方法也容易导致状态不一致。

需要详细了解的小伙伴可以阅读以下文章:为什么废弃react生命周期函数?

详解旧的生命周期

一、三个阶段

1. 初始化阶段 :  由ReactDOM.render()触发---初次渲染,会调用以下钩子函数

1. constructor()

2. componentWillMount()

3. render()

4. componentDidMount()

2. 更新阶段 : 由组件内部this.setSate()或父组件重新render触发,会调用以下钩子函数

1. shouldComponentUpdate()

2. componentWillUpdate()

3. render()

4. componentDidUpdate()

3. 卸载组件 : 由ReactDOM.unmountComponentAtNode()触发

1. componentWillUnmount()

二、详解各个钩子函数

componentWillMount()componentWillReceiveProps()componentWillUpdate()三个钩子函数不再推荐使用,故不再详细解释说明。

  • constructor()

constructor():构造函数,通常用于初始化组件的状态和绑定方法。

constructor(props) { 
    super(props);
    this.state = { count: 0 }; 
    this.handleClick = this.handleClick.bind(this); 
}

在函数体中,需要先写super(props); ,想深入探究的小伙伴可以点我

  • render()

render():是用来返回组件的UI结构,它是一个纯函数,其中不应该包含任何副作用或改变状态的操作。

import React,{Component} from 'react'

export default class Hello extends Component{
	render(){
		return <h2>Hello,React!</h2>
	}
}
  • componentDidMount()

componentDidMount():这个函数是在组件挂载到DOM后执行的,可以在这里获取数据、进行一些异步请求或DOM操作。

componentDidMount() { 
    // 发起API请求或其他初始化操作 
    fetchData().then(data => { 
        this.setState({ data 
        }); 
    }); 
}
  • shouldComponentUpdate()

shouldComponentUpdate(nextProps, nextState):这个函数是用来判断组件是否需要重新渲染,返回一个布尔值,可以优化性能。

shouldComponentUpdate(nextProps, nextState) {
    // 这里假设props有一个min属性,表示计数器的最小值
    if (nextProps.min !== undefined && nextState.count < nextProps.min) {
      return false;
    }
    return true;
  }

细心观察旧的生命周期图的小伙伴注意到了此钩子函数旁边有个setState(),在组件中,每当调用this.setState()方法时,就会触发shouldComponentUpdate(),如果函数返回true就更新状态,否则不更新。

forceUpdate():强制更新

当调用forceUpdate()时,会直接来到componentWillUpdate()钩子函数。

何时使用: 只想更新一下组件,但是不想对状态作出任何的更改,就可以调用,通过this.forceUpdate()直接调用

  • componentDidUpdate()

componentDidUpdate(prevProps, prevState):组件更新后触发,用于处理更新后的操作。

componentDidUpdate(prevProps, prevState) {
    console.log('组件已更新完毕');
    if (prevProps.id !== this.props.id) { 
        // 处理props变化的逻辑 
        console.log('props.id变了');
    } 
}
  • componentWillUnmount()

componentWillUnmount():这个函数是在组件卸载前执行的,可以在这里进行一些清理工作,比如取消订阅、清除定时器、取消异步请求或移除事件监听器等。

详解新生命周期

一、三个阶段

1. 初始化阶段 :  由ReactDOM.render()触发---初次渲染

1. constructor()

2. getDerivedStateFromProps

3. render()

4. componentDidMount()

2. 更新阶段 : 由组件内部this.setSate()或父组件重新render触发

1. getDerivedStateFromProps

2. shouldComponentUpdate()

3. render()

4. getSnapshotBeforeUpdate

5. componentDidUpdate()

3. 卸载组件 : 由ReactDOM.unmountComponentAtNode()触发

1. componentWillUnmount()

二、详解新增的钩子函数

部分钩子函数用法与旧生命周期中的用法相似,不再重复说明。

变化:

  • componentDidUpdate()

componentDidUpdate(prevProps,prevState,snapshot):它在组件更新(即render() 方法执行后)后被调用。它接收三个参数:prevPropsprevStatesnapshot。与旧的钩子函数相比,多了一个参数snapshot

componentDidUpdate(prevProps, prevState, snapshot) {
    if (this.props.data !== prevProps.data) {
      console.log('this.props中的数据变了');
    }

    // 使用getSnapshotBeforeUpdate()的返回值
    if (snapshot !== null) {
      console.log('Snapshot from getSnapshotBeforeUpdate:', snapshot);
    }
}

说明:如果getSnapshotBeforeUpdate()有返回值,它会成为componentDidUpdate()的第三个参数,你可以在这里使用它。

新增:

  • getDerivedStateFromProps()

getDerivedStateFromProps(nextProps,prevState):是一个静态方法,用于在组件接收新的props时计算并返回新的state。这个方法在React 16.3版本之后引入,用来替代不推荐使用的componentWillReceiveProps()方法。

class MyComponent extends React.Component { 
    static getDerivedStateFromProps(nextProps, prevState) { 
        // 根据 nextProps 和 prevState 计算并返回新的 state 
        if (nextProps.value !== prevState.value) { 
            return { value: nextProps.value }; 
        } 
        return null; // 如果不需要更新 state,返回 null 
    } 
    
    constructor(props) { 
        super(props); 
        this.state = { 
            value: props.value, 
        }; 
    }
    
    render() { 
        return <div>{this.state.value}</div>; 
    } 
}

以下是getDerivedStateFromProps() 的主要特点和使用方式:

  • 静态方法getDerivedStateFromProps() 是一个静态方法,因此不能访问实例的this,它只接收两个参数:nextProps 和 prevState
  • 计算新的state:通常,你可以在这个方法内部根据nextProps 和 prevState 来计算并返回新的state。这个新的state将在组件更新时应用。
  • 不触发副作用:与componentDidUpdate() 不同,getDerivedStateFromProps() 不应执行副作用,如发起网络请求。它只用于计算state。
  • 适用于控制组件内部状态getDerivedStateFromProps() 主要用于控制组件内部的状态,以确保它与外部传入的props保持同步。
  • getSnapshotBeforeUpdate()

getSnapshotBeforeUpdate(nextProps,prevState):它在组件更新(即将应用新props或state并重新渲染)之前触发。它允许你捕获组件更新前的一些信息,并在组件更新后使用这些信息。

class MyComponent extends React.Component {
	constructor(props) {
	  super(props);
	  this.myRef = React.createRef();
	}
  
	getSnapshotBeforeUpdate(prevProps, prevState) {
	  // 捕获组件更新前的滚动位置
	  if (prevProps.items.length < this.props.items.length) {
		const scrollHeight = this.myRef.current.scrollHeight;
		const scrollTop = this.myRef.current.scrollTop;
		return { scrollHeight, scrollTop };
	  }
	  return null;
	}
  
	componentDidUpdate(prevProps, prevState, snapshot) {
	  // 使用snapshot来恢复滚动位置
	  if (snapshot !== null) {
		this.myRef.current.scrollTop = snapshot.scrollTop + (this.myRef.current.scrollHeight - snapshot.scrollHeight);
	  }
	}
  
	render() {
	  // 使用ref来获取DOM元素的引用
	  return <div ref={this.myRef}>{/* 组件内容 */}</div>;
	}
}

示例中,getSnapshotBeforeUpdate() 用于捕获滚动位置,然后在componentDidUpdate() 中使用snapshot来恢复滚动位置,以确保用户在滚动列表时不会在更新后失去滚动位置。

以下是关于getSnapshotBeforeUpdate() 的主要特点和用法:

  • 触发时机getSnapshotBeforeUpdate() 在render() 方法被调用后、组件DOM更新前触发,通常用于在更新前捕获一些DOM信息。
  • 接收两个参数:这个生命周期方法接收两个参数:prevPropsprevState。你可以使用这些参数来比较前后的props和state。
  • 返回值getSnapshotBeforeUpdate() 方法应该返回一个值(通常是一个对象),它将成为componentDidUpdate() 方法的第三个参数。这个返回值通常用于保存一些DOM相关的信息,比如滚动位置。
  • 通常和componentDidUpdate()一起使用getSnapshotBeforeUpdate() 结合componentDidUpdate(prevProps, prevState, snapshot) 使用,snapshot参数是getSnapshotBeforeUpdate() 的返回值。你可以在componentDidUpdate() 中使用snapshot来执行DOM操作或其他一些操作。

总结

通过本篇文章的学习,相信小伙伴们已经全面了解了React生命周期的执行流程以及各个生命周期函数的作用。

通过正确地使用这些生命周期函数,我们可以更好地控制组件的行为,提高应用性能,同时保持代码的可读性和可维护性。希望本文对你理解React生命周期有所帮助,也能够在实际项目中灵活运用,构建出更好的用户体验。

如果你有任何问题或疑惑,也请随时在评论区提问,我将尽力解答。感谢阅读!

转载自:https://juejin.cn/post/7285540804734468150
评论
请登录