React 类组件的生命周期

简介: React 类组件的生命周期

1、constructor() :初始化 props、state、绑定 this

       React 类组件的 constructor() 生命周期,主要用途是 初始化 props、初始化 state、绑定 this。若该类组件只需要初始化 props ,则 constructor 可以不写。如果 constructor 中需要写其他东西,比如:声明 state、绑定 this,则 constructor 不能省略。constructor 接收一个 props 外部数据的参数,具体使用方法如下:

class Welcome extends React.Component {
  constructor(props){    //如果没有额外的代码,这三行可省略,不写也可以初始化props数据
    super(props);        //初始化 props
  }
}
class Welcome extends React.Component {
  constructor(props){
    super(props);     //如果constructor中不只需要初始化 props,则那三行不可省略
    this.state = {    //初始化 state,只能通过这种 this.state = {} 的方式初始化state
        n: 1;
    }
  }
}
class Welcome extends React.Component {            class Welcome extends React.Component {
  constructor(props){                                constructor(props){
    super(props);                                      super(props);
    this.state = {}                                    this.state = {}
    //bind this,可以写成右面这种语法                  }
    this.onClick = this.onClick.bind(this);          onClick = ()=> {}    //和左边是等价的,推荐这种
  }                                                }
}

2、shouldComponentUpdate() :return false 阻止更新

       React 类组件的 shouldComponentUpdate() 生命周期,主要用途是:允许开发人员手动判断是否要进行组件更新。shouldComponentUpdate() 接收两个参数,一个是新的 props,一个是新的 state,该函数如果返回 true 表示不阻止 UI 更新,返回 false 表示阻止 UI 更新。我们可以根据应用场景灵活地设置返回值,以避免不必要的更新。


       what?这是什么鬼逻辑,React 为什么会需要开发人员去决定组件是否更新?我们需要来看一个示例:

class App extends React.Component {    //React.PureComponent内置了shouldComponentupdate钩子
    constructor(props){
        super(props);     //初始化props
        this.state = {    //声明 state
            n: 1
        };
    }
    onClick = () => {
        this.setState(state =>({n:state.n+1}))    //进行 +1 操作
        this.setState(state =>({n:state.n-1}))    //再进行 -1 操作
    };
    shouldComponentUpdate(newprops, newstate){    //nextprops、nextstate
        if(newstate.n  === this.state.n){
            return false;
        }else{
            return true;
        }
    }
    render(){
        console.log('render了一次');
        return (
            <div>
                {this.state.n}
                <button onClick={this.onClick}>+1-1</button>
            </div>
        );
    }
}

       有时候在类组件中某个操作功能比较复杂,但是它最终的操作结果和一开始一样,比如上面的 +1-1 操作。这个时候虽然数据从最开始 {n:1} 变成了 内存地址不同 的 {n:1},但其值实际上并没有发生改变,所以就不需要重新渲染,这个时候就需要 shouldComponentUpdate 手动阻止 UI 更新,以 提高性能。


       正常情况下,如果不加这一层 shouldComponentUpdate 钩子,React 检测到 +1-1 后的结果内存地址不一样,就会认为数据发生了变化,然会后去执行 render() 生成新的虚拟 DOM 对象,然后进行新旧虚拟 DOM 对比,如果新旧 DOM 不同就更新 UI。如果手动加上 shouldComponentUpdate 钩子,则就不需要后面的 render() 步骤,从而提高性能。


       疑问:React 这么牛,为什么不能内置这个功能呢?将 newState 和 this.state 的每个属性都对比一下,如果全都相等,就不更新,如果有一个不等,就更新。React 确实内置了,这个功能叫做 React.PureComponent,可以代替 React.Component。PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。

3、render() :创建虚拟 DOM

       React 类组件的 render() 生命周期,主要用途是展示视图,它能返回一个虚拟 DOM 对象:return(<div>...</div>),但是这个元素 只能有一个根元素,如果需要返回两个根元素,就要用 <React.Fragment> 包起,<React.Fragment/>可以缩写成 <></>。这个包裹的元素只是占位符,实际上并不会被渲染到页面上。


       render() 里面可以写 if...else、三木运算符,但是不能直接写 for 循环,需要用数组的方式,可以写 array.map(循环)

render() {                                                  render() {
    let message;                                                return (
    if(this.state.n%2 = 0) {                                        <>
        message=<div>偶数</div>;                                    {this.state.n%2===0 ?
    }else{                                                              <div>偶数</div> :
        message=<span>奇数</span>;                                      <span>奇数</span>}
    }                                                               <button onClick = {this.onClick}>+1</button>
    return (                                                        </>
        <>                                                      )
        {message}                                          }
        <button onClick = {this.onClick}>+1</button>
        </>
    )
}
render(){    //在循环时必须要写 key,提高 Dom diff 性能
    return this.state.array.map( item => <span key={item}> {item} </span>)
}

4、componentDidMount() :组件已经出现在页面

       React 类组件的 componentDidMount() 生命周期,主要用途是:在元素插入页面后执行代码,这些代码一般是要依赖 DOM(比如:你想获取 div 的高度,就最好在这里写此处)。可以发起 加载数据 的 AJAX 请求(官方推荐)。


⚠ 区别于 componentDidUpdate 生命周期,该生命周期在页面在首次渲染时,一会被执行。

componentDidMount(){
    const div = document.getElementById('xxx')    //可以使用ref获取元素的
    const {width} = div.getBoundingClientRect()
    this.setState(() => {width: 100})
}
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();    //使用React.createRef()创建refs
  }
  render() {
    return <div ref={this.myRef} />;    //将 ref 挂到某个元素上
  }
  componentDidMounted(){
    const div = this.divRef.current;    //通过 current 属性对节点的引用进行访问
    const {width} = div.getBoundingClientRect();
    this. setState({width});
  }
}

5、componentDidUpdate() :组件已更新

       React 类组件的 componentDidUpdate() 生命周期,会在视图更新后执行相关代码,此处也可以发起用于 更新数据 AJAX 请求(比如用户 id 变了,需要获取新的用户信息)。如果在此钩子内 setState 可能会引起无限循环,除非放在 if 里,所以最好不要在该钩子内改数据。若 shouldComponentUpdate() 生命周期返回 false,表示阻止 UI 更新,则不触发此钩子。


⚠ 区别于 componentDidMount() 生命周期,该钩子在页面首次渲染时是 不会 被执行的。

componentDidupdate(prevProps, prevstate, snapshot)

6、componentWillUnmount() :组件将死

       React 类组件的 componentWillUnmount() 生命周期,主要用途是:组件将要被移出页面然后被销毁时执行代码。注意:unmount 过的组件不会再次 mount,因为它也被从内存中销毁了。

- 如果你在 componentDidMount 里面监听了 window scroll
    那么你就要在 componentWillUnmount里面取消监听
- 如果你在 componentDidMount 里面创建了 Timer
    那么你就要在 componentWillUnmount 里面取消 Timer
- 如果你在 componentDidMount里面创建了AJAX请求
    那么你就要在 componentWillUnmount里面取消请求

7、分阶段看生命周期钩子的执行顺序

// 首次渲染:
// constructor -> render -> componentDidMount
// 再次渲染:
// 1. props change -\                        /--结束
// 2. setState() ---->shouldComponentUpdate-<
// 3. forceUpdate()-/                        \--render-> 更新UI->componentDidUpdate
// 销毁:
// componentWillUnmount
目录
相关文章
|
3天前
|
前端开发 JavaScript 测试技术
React 分页组件 Pagination
本文介绍了如何在 React 中从零构建分页组件,涵盖基础概念、常见问题及解决方案。通过示例代码详细讲解了分页按钮的创建、分页按钮过多、初始加载慢、状态管理混乱等常见问题的解决方法,以及如何避免边界条件、性能优化和用户反馈等方面的易错点。旨在帮助开发者更好地理解和掌握 React 分页组件的开发技巧,提升应用的性能和用户体验。
20 0
|
1月前
|
前端开发 开发者
React 函数组件与类组件对比
【10月更文挑战第4天】本文详细比较了React中的函数组件与类组件。函数组件是一种简单的组件形式,以纯函数的形式返回JSX,易于理解与维护,适用于简单的UI逻辑。类组件则是基于ES6类实现的,需要重写`render`方法并能利用更多生命周期方法进行状态管理。文章通过示例代码展示了两者在状态管理与生命周期管理上的差异,并讨论了常见的问题如状态更新异步性与生命周期管理的复杂性,最后给出了相应的解决方法。通过学习,开发者可以根据具体需求选择合适的组件类型。
54 8
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
161 2
|
1月前
|
前端开发 JavaScript
React 组件生命周期
React 组件生命周期
29 0
|
8天前
|
移动开发 前端开发 API
React 拖拽组件 Drag & Drop
本文介绍了在 React 中实现拖拽功能的方法,包括使用原生 HTML5 Drag and Drop API 和第三方库 `react-dnd`。通过代码示例详细讲解了基本的拖拽实现、常见问题及易错点,帮助开发者更好地理解和应用拖拽功能。
30 9
|
2天前
|
前端开发 UED 开发者
React 分页组件 Pagination
本文介绍了如何在 React 中实现分页组件,从基础概念到常见问题及解决方案。分页组件用于将大量数据分成多个页面,提升用户体验。文章详细讲解了分页组件的基本结构、快速入门步骤、以及如何处理页面跳转不平滑、页码过多导致布局混乱、边界条件处理和数据加载延迟等问题。通过本文,读者可以全面了解并掌握 React 分页组件的开发技巧。
7 2
|
6天前
|
设计模式 前端开发 编译器
与普通组件相比,React 泛型组件有哪些优势?
与普通组件相比,React 泛型组件有哪些优势?
22 6
|
12天前
|
前端开发 JavaScript
react 组件的生命周期
React组件的生命周期包括从创建到销毁的各个阶段,如挂载(mounting)、更新(updating)和卸载(unmounting)。每个阶段都有特定的方法,用于控制组件的行为和状态,确保高效、有序地渲染和管理UI。
|
14天前
|
前端开发 JavaScript 安全
学习如何为 React 组件编写测试:
学习如何为 React 组件编写测试:
32 2
|
21天前
|
前端开发 JavaScript 测试技术
React 高阶组件 (HOC) 应用
【10月更文挑战第16天】高阶组件(HOC)是 React 中一种复用组件逻辑的方式,通过接受一个组件并返回新组件来实现。本文介绍了 HOC 的基础概念、核心功能和常见问题,包括静态方法丢失、ref 丢失、多个 HOC 组合和 props 冲突的解决方案,并提供了具体的 React 代码示例。通过本文,读者可以更好地理解和应用 HOC,提高代码的复用性和可维护性。
50 8