目录
实例化阶段
存在期
销毁
React v.16生命周期
首页 web前端 js教程 react生命周期的全面了解(附代码)

react生命周期的全面了解(附代码)

Apr 03, 2019 am 10:05 AM
javascript react.js

本篇文章给大家带来的内容是关于react生命周期的全面了解(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

一个React组件的生命周期分为三个部分:实例化、存在期和销毁时。

实例化阶段

客户端渲染时,如下依次被调用

  • getDefaultProps()
  • getInitialState()
  • componentWillMount()
  • render()
  • componentDidMount()

服务端渲染

  • getDefaultProps()
  • getInitialState()
  • componentWillMount()
  • render()

注意:componentDidMount()不会再服务端被渲染;

getDefaultProps

对于每个组件实例来讲,这个方法只会调用一次,该组件类的所有后续应用,getDefaultPops 将不会再被调用,其返回的对象可以用于设置默认的props值。

var Hello = React.creatClass({
    getDefaultProps: function(){
        return {
            name: 'pomy',
            git: 'dwqs'
        }
    },
    
    render: function(){
        return (
            <p>Hello,{this.props.name},git username is {this.props.dwqs}</p>
        )
    }
});

ReactDOM.render(<Hello />, document.body);
登录后复制

也可以在挂载组件的时候设置 props。

var data = [{title: 'Hello'}];
<Hello data={data} />
登录后复制

或者调用 setProps (一般不需要调用)来设置其 props

var data = [{title: 'Hello'}];
var Hello = React.render(<Demo />, document.body);
Hello.setProps({data:data});
登录后复制

但只能在子组件或组件树上调用 setProps。别调用 this.setProps 或者 直接修改 this.props。将其当做只读数据。

React通过 propTypes 提供了一种验证 props 的方式,propTypes 是一个配置对象,用于定义属性类型:

var survey = React.createClass({
    propTypes: {
        survey: React.PropTypes.shape({
            id: React.PropTypes.number.isRequired
        }).isRequired,
        onClick: React.PropTypes.func,
        name: React.PropTypes.string,
        score: React.PropTypes.array
        ...
    },
    
    //...
})
登录后复制

或者

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class BetterImage extends Component{...}

BetterImage.PropTypes={
  src: PropTypes.string,
  center: PropTypes.bool,
  loadingImage: PropTypes.string,
  defaultImage: PropTypes.string,
  onLoad: PropTypes.func,
  onError: PropTypes.func,
  onComplete: PropTypes.func
}
BetterImage.defaultProps={
  ....
}
登录后复制

getInitialState

对于组件的每个实例来说,这个方法的调用有且只有一次,用来初始化每个实例的 state,在这个方法里,可以访问组件的 props。每一个React组件都有自己的 state,其与 props 的区别在于 state只存在组件的内部,props 在所有实例中共享。

getInitialState 和 getDefaultPops 的调用是有区别的,getDefaultPops 是对于组件类来说只调用一次,后续该类的应用都不会被调用,而 getInitialState 是对于每个组件实例来讲都会调用,并且只调一次。

var LikeButton = React.createClass({
  //初始化State
  getInitialState: function() {
    return {liked: false};
  },
  
  handleClick: function(event) {
    //设置修改State
    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>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);
登录后复制

每次修改 state,都会重新渲染组件,实例化后通过 state 更新组件,会依次调用下列方法:

1、shouldComponentUpdate
2、componentWillUpdate
3、render
4、componentDidUpdate
登录后复制
  • componentWillMount

在渲染前调用,在客户端也在服务端。React 官方正式发布了 v16.3 版本。在这次的更新中,除了前段时间被热烈讨论的新 Context API 之外,新引入的两个生命周期函数 getDerivedStateFromProps,getSnapshotBeforeUpdate 以及在未来 v17.0 版本中即将被移除的三个生命周期函数 componentWillMount,componentWillReceiveProps,componentWillUpdate .

在这个生命周期中你会遇到一下问题:

a.首屏无数据导致白屏
  在 React 应用中,许多开发者为了避免第一次渲染时页面因为没有获取到异步数据导致的白屏,而将数据请求部分的代码放在了 componentWillMount 中,希望可以避免白屏并提早异步请求的发送时间。但事实上在 componentWillMount 执行后,第一次渲染就已经开始了,所以如果在 componentWillMount 执行时还没有获取到异步数据的话,页面首次渲染时也仍然会处于没有异步数据的状态。换句话说,组件在首次渲染时总是会处于没有异步数据的状态,所以不论在哪里发送数据请求,都无法直接解决这一问题。而关于提早发送数据请求,官方也鼓励将数据请求部分的代码放在组件的 constructor 中,而不是 componentWillMount。
 若是为了改善用户体验曾经用过的解决方法有两个:

方法一:异步请求组件,使用nprogress 添加加载动画;

import React, { Component } from 'react'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import './customNprogress.styl'

NProgress.configure({ showSpinner: false })

export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    state = {
      component: null
    }

    async componentDidMount() {
      NProgress.start()
      const { default: component } = await importComponent()
      NProgress.done()

      this.setState({ component })
    }

    render() {
      const C = this.state.component

      return C ? <C {...this.props} /> : null
    }
  }

  return AsyncComponent
}

const AsyncNotFound = asyncComponent(() => import(/* webpackChunkName: "NotFound" */ '@/routes/NotFound'))
登录后复制

方法二:使用  onreadystatechange  去监听 readyState,在资源加载完成之前加载一个只有框架的静态页面,页面不请求数据。当数据请求完成之后再将路由切换到真实的首页。

  function listen () {
    if (document.readyState == 'complete') { // 资源加载完成
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={Index}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    } else { // 资源加载中
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={FirstScreen}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    }
}

document.onreadystatechange = listen
登录后复制

具体参考解决React首屏加载白屏的问题

b.事件订阅

另一个常见的用例是在 componentWillMount 中订阅事件,并在 componentWillUnmount 中取消掉相应的事件订阅。但事实上 React 并不能够保证在 componentWillMount 被调用后,同一组件的 componentWillUnmount 也一定会被调用。一个当前版本的例子如服务端渲染时,componentWillUnmount 是不会在服务端被调用的,所以在 componentWillMount 中订阅事件就会直接导致服务端的内存泄漏。另一方面,在未来 React 开启异步渲染模式后,在 componentWillMount 被调用之后,组件的渲染也很有可能会被其他的事务所打断,导致 componentWillUnmount 不会被调用。而 **componentDidMount 就不存在这个问题,在 componentDidMount 被调用后,componentWillUnmount 一定会随后被调用到,并根据具体代码清除掉组件中存在的事件订阅。**

render

该方法会创建一个虚拟DOM,用来表示组件的输出。对于一个组件来讲,render方法是唯一一个必需的方法。render方法需要满足下面几点:

  • 只能通过 this.props 和 this.state 访问数据(不能修改)
  • 可以返回 null,false(这种场景下,react渲染一个
  • 只能出现一个顶级组件,不能返回一组元素
  • 不能改变组件的状态
  • 不能修改DOM的输出

render方法返回的结果并不是真正的DOM元素,而是一个虚拟的表现,类似于一个DOM tree的结构的对象。react之所以效率高,就是这个原因。

render执行情况如下:

1. 首次加载
2. setState改变组件内部state。
   注意: 此处是说通过setState方法改变。
3. 接受到新的props

注意:因为数据是异步的情况,会导致组件重复渲染

componentDidMount

该方法不会在服务端被渲染的过程中调用。该方法被调用时,已经渲染出真实的 DOM,可以再该方法中通过 this.getDOMNode() 访问到真实的 DOM(推荐使用 ReactDOM.findDOMNode())。

var data = [..];
var comp = React.createClass({
    render: function(){
        return <imput .. />
    },
    componentDidMount: function(){
        $(this.getDOMNode()).autoComplete({
            src: data
        })
    }
})
登录后复制

由于组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性:

var Area = React.createClass({
    render: function(){
        this.getDOMNode(); //render调用时,组件未挂载,这里将报错
        
        return <canvas ref=&#39;mainCanvas&#39;>
    },
    componentDidMount: function(){
        var canvas = this.refs.mainCanvas.getDOMNode();
        //这是有效的,可以访问到 Canvas 节点
    }
})
登录后复制

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。如果ref回调函数以inline函数的方式来指定,那么在组件更新的时候ref回调会被调用2次。第一次回调的时候传入的参数是null,而第二次的时候才真正的传入DOM节点

更多了解ref使用
从React官方文档看 refs 的使用和未来
获取真实dom,并获取dom css 三种方法

存在期

此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变,你将会看到下面的方法依次被调用;

  1. componentWillReceiveProps()
  2. shouldComponentUpdate()
  3. componentWillUpdate()
  4. render()
  5. componentDidUpdate()

componentWillReceiveProps

当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用。

componentWillReceiveProps: function(nextProps){
    if(nextProps.checked !== undefined){
        this.setState({
            checked: nextProps.checked
        })
    }
}
登录后复制

了解更多点击此处

shouldComponentUpdate

shouldComponentUpdate函数是重渲染时render()函数调用前被调用的函数,它接受两个参数:nextProps和nextState,分别表示下一个props和下一个state的值。并且,当函数返回false时候,阻止接下来的render()函数及后面的 componentWillUpdate,componentDidUpdate 方法的调用,阻止组件重渲染,而返回true时,组件照常重渲染。

了解更多点击此处--真的讲的好

componentWillUpdate

这个方法和 componentWillMount 类似,在组件接收到了新的 props 或者 state 即将进行重新渲染前,componentWillUpdate(object nextProps, object nextState) 会被调用,注意不要在此方面里再去更新 props 或者 state。

componentDidUpdate

这个方法和 componentDidMount 类似,在组件重新被渲染之后,componentDidUpdate(object prevProps, object prevState) 会被调用。可以在这里访问并修改 DOM。

销毁

componentWillUnmount

每当React使用完一个组件,这个组件必须从 DOM 中卸载后被销毁,此时 componentWillUnmout 会被执行,完成所有的清理和销毁工作,在 componentDidMount 中添加的任务都需要再该方法中撤销,如创建的定时器或事件监听器。

当再次装载组件时,以下方法会被依次调用:

1、getInitialState
2、componentWillMount
3、render
4、componentDidMount

React v.16生命周期

constructor(props) // 初始化参数

componentWillMount()

render() // 第一次渲染 

componentDidMount()

**当父组件向子组件传入props发生改变后,依次调用**

componentWillReceiveProps(nextProps)

shouldComponentUpdate(nextProps, nextState) 

componentWillUpdate()

render() //子组件更新渲染

componentDidUpdate()

**当组件自身state发生变化后**

componentWillUpdate()

render() //组件再次更新渲染

componentDidUpdate()


当组件卸载

componentWillUnmount()
登录后复制

与低于React16版本的比较

  1. React16新的生命周期弃用了componentWillMount、componentWillReceiveProps,componentWillUpdate
  2. 新增了getDerivedStateFromProps、getSnapshotBeforeUpdate来代替弃用的三个钩子函数(componentWillMount、componentWillReceivePorps,componentWillUpdate)
  3. React16并没有删除这三个钩子函数,但是不能和新增的钩子函数(getDerivedStateFromProps、getSnapshotBeforeUpdate)混用,React17将会删除componentWillMount、componentWillReceivePorps,componentWillUpdate
  4. 新增了对错误的处理(componentDidCatch)

【相关推荐:react视频教程

以上是react生命周期的全面了解(附代码)的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

javascript中如何使用insertBefore javascript中如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。

如何在JavaScript中获取HTTP状态码的简单方法 如何在JavaScript中获取HTTP状态码的简单方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP状态码获取方法简介:在进行前端开发中,我们常常需要处理与后端接口的交互,而HTTP状态码就是其中非常重要的一部分。了解和获取HTTP状态码有助于我们更好地处理接口返回的数据。本文将介绍使用JavaScript获取HTTP状态码的方法,并提供具体代码示例。一、什么是HTTP状态码HTTP状态码是指当浏览器向服务器发起请求时,服务

See all articles