React 学习(四) ---- 生命周期函数

  现在我们能修改状态,页面可以进行交互了,但是还有一种状态改变没有解决,那就是倒计时效果,时间一直在变化,组件状态也一直在改变,但我们什么都没有做,如果要实现这样的效果,需要怎么处理? 我们都知道,改变状态用的是setState,  上次讲的加减操作是在把它写到事件处理函数中来改变状态的,但现在没有什么事件供我们调用,因为我们没有做任何操作,它却一直在变化,现在要做的就是找一个机会或入口,来写setState 函数, 这个机会就是组件的生命周期函数。

  生命周期也是来源于对我们对现实生活的思考, 对于一个有生命的事物来说,它都会经历从生到死的过程,在这个过程中又分不同的阶段,每一个阶段都有不同的事情要做。就拿我们自己来说,都会经历少年,中年,老年三个阶段,少年时,我们的重点,就是上学, 中年的重点是工作,老年可能就是帮助我们一下代了。对于组件来说,它是有状态的,也就是有生命的,就会分为不同的阶段,具体分为哪些阶段,React 已经给我们定义好了,就是提供了一系列的函数,每一个阶段(函数)都有不同的重点,要做什么事性。这就给我们提供了机会,我们可以做自己的事。 这些函数就叫生命周期函数, 生命周期函数是由React 提供的, 它就负责管理,到了哪个阶段,React 会自动调用这些函数, 我们要做的就是在这些函数中,定义要做的事性。这就给我们提供了机会,来改变状态。

  组件的生命周期,它会经历三个阶段, 装载阶段,更新阶段,卸载阶段:

    装载阶段: 就是组件初次渲染到页面上的阶段。首次加载页面时,页面是空白的,然后经过几秒时间,页面中显示内容。这一过程称之为装载。

    更新阶段:用户在页面上进行交互,组件重新渲染的过程。比如用户点击加号, 页面中的数字由1变成2.

    卸载阶段: 组件从页面中删除。点击按钮显示一个新的组件,原来的组件就删除了。

  先来看一下挂载阶段,它又具体分为四个阶段,进入构造函数,将要挂载,进行渲染,挂载完成。

  进入构造函数:就是每个组件中的构造函数。它的主要作用就是初始化状态,当然它还有一个props参数,它可以使用组件传递过来的props,因此也可以用props进行初始化。

  将要挂载:React 提供了compontentWillMount 函数,不过一般不会在这时做什么。

  进行渲染:就是我们每一个组件中render 函数,它是至关重要的,因为我们写一个组件的目的,就是要渲染到页面上一些东西,它只有返回一个虚拟DOM, ReactDOM 才能根据它构建出真实的DOM渲染到页面上。它会根据props 和state 渲染出react element, 指导react渲染出真正的dom. 但总存在特殊的情况,组件不需要渲染什么东西,如验证用户有没有登录的组件,它确实不需要返什么,我们只是根据它进行跳转到不同的页面,这时直接在render 函数中返回null.

  挂载完成:React 提供了componentDidMounti函数: 当真实的DOM 渲染到页面上会触发它。 需要注意的是render 函数在调用完成后,componentDidMount 并不会立刻调用,而是在当所有的render函数都调用完华之后,组件的componentDidMount 才会调用。 写一下代码会看得比较清楚,这也是我第一次明白地认识了react的挂载生命周期。

  在讲state时,我们写了一个Counter,现在再写一个组件CounterWrapper, 它包含Counter 组件,因为此时CounterWrapper 是包含Counter组件的,我们也可以称CounterWrapper 为父组件,Counter 为子组件,为了更能清楚地明白生命周期函数,我们父组件多包含几个Counter. 为了对每一个Counter 进行区分,我们给它们传一个caption 和initValue 参数。 在父组件CounterWrapper 中 由于没有state, 我只写了render函数和ComponentDidMount 函数,而在子组件Counter中,它有state, 有完整的生命周期函数,依次写了四个阶段,constructor, componentWillMount, render, componentDidMount, 当然它们只是console.log一下信息,看一下执行的过程。

<script type="text/babel">

// 子组件counter
class Counter extends React.Component {

    constructor(props) {
        super(props);
        console.log(`进入子组件Counter的构造函数constructor ----- ${props.caption}`);
        this.state = {
            count: props.initValue || 0
        }
    }
    // 生命周期函数
    componentWillMount() {
        console.log(`进入子组件Counter的componentWillMount ----- ${this.props.caption}`);
    }
    componentDidMount() {
        console.log(`进入子组件Counter的componentDidMount ----- ${this.props.caption}`);
    }
   render() {
        console.log(`进入子组件Counter的render ----- ${this.props.caption}`);
        const buttonStyle = {
            margin: ‘10px‘
        };

    return (
      <div><button style={buttonStyle} >+</button>
        <button style={buttonStyle} value = {5}>-</button>
        <span>{this.props.caption}count: {this.state.count}</span>
      </div>
    );
  }
}

// 父组件CounterWrapper
class CounterWrapper extends React.Component {

    render(){
        console.log(‘进入父组件CounterWrapper的render 函数‘);
        return (<div>
            <Counter caption="第一个" initValue={3}></Counter>
            <Counter caption="第二个" initValue={6}></Counter>
            <Counter caption="第三个" initValue={9}></Counter>
        </div>)
    }

    componentDidMount() {
        console.log(‘进入父组件CounterWrapper的 componentDidMount 函数‘);
    }
}

   ReactDOM.render(<CounterWrapper />, document.getElementById(‘root‘));
</script>

  控制台输出如下信息

  

  可以看到它先进入的是父组件CounterWrapper 的render 函数,然后再进入第一个子组件的constructor, componentWillMount和 render, 再进入第二个子组件的constructor, componentWillMount和 render函数,再进入第三个子组件的constructor, componentWillMount和 render函数, 最后才是每一个子组件的componentDidMount, 第二个子组件的ccomponentDidMount函数, 第三个子组件的ccomponentDidMount函数,最后的最后是父组件的CompoentDidMount.

  我们惊奇地发现,组件的挂载生命周期并不是依次调用的,render 函数后面并不是紧紧根随着componentDidMount 函数。只有当三个组件的render函数都调用完成后,三个组件的componentDidMount 才连在一起被调用。 只有当所有的子组件的componentDidMount都调用了,父组件的componetDidMount 才会被调用。在componentDidMount 函数的调用上,我一直存在误解,以为render 函数调用后,立即执行它,并有父组件的componentDidMount优于子组件的componentDidMount 执行,真是太想当然了。

  现在再来想一下为什么会有这样的设计,当使用componentDidMount 的时候,我们听得最多的一句话可能就是,在这里,你可以操作真实的DOM了,换句话说,当 组件compoentDidMount的时候,真实的DOM 已经渲染完毕了,整个页面都已经渲染完成了。整个页面就意味着整个DOM树都已经构建完成了,注意这里是整个DOM树。当React进入到组件的render 函数时,它只知道当前组件长什么样子,而不会知道整个DOM树长什么样子,所以它只能接着找到第二个组件render, 因为后面有第三个子组件,它还是不知道整个DOM树长什么样子,所以它还要找到第三个组件render,  也就是说它会把所有的组件都循环一遍,直到能够构建整个DOM树,它才会渲染真实的DOM, 这也是最为省事的办法,如果它找到一个渲染一个,后面的组件再对前面的组件有影响,它要把前面的做法再来一次,效率低下。一次渲染就OK了。 渲染之后,肯定是最深层的组件先完成,只有小的完成了才能组成大的,所以最深层的组件的componentDidMount 先执行, 最外层的最后执行。这让我们想成了JS事件处理阶段,当构建DOM树的过程中,它是捕获阶段,从外面找到最里面,而在渲染真实的DOM的时候,componentDidMount的时候,它是冒泡阶段, 从最里面到最外面。

  现在再来看更新阶段,当挂载阶段完成后,用户看到页面了。但如果要让页面有更好的交互性,那还要能更改状态或属性,重新渲染了组件,这就是更新阶段了。更新阶段又依次分为下面几个阶段:

  1, 将要接收属性 --> componentWillRecieveProps

  2,  组件应不应该更新 ---> shouldCompoentUpdate

  3,  组件将要更新 ---> componentWillUpdate

  4, 组件进行渲染 --> render

  5, 组件渲染完成 --> componentDidUpdate

原文地址:https://www.cnblogs.com/SamWeb/p/8642857.html

时间: 2024-08-27 08:23:57

React 学习(四) ---- 生命周期函数的相关文章

react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)

react学习小结 本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之前对react使用不多,正好我目前在做的项目也在使用react+redux,借着这个机会系统的学习下react+redux. react是什么 react是一个JavaScript类库,通过react,我们可以构建可组合的UI,也就是说,我们可以通过重用组件来组合出我们的UI.可以说react的核心便是

react学习(四)Element和虚拟DOM

参考:https://facebook.github.io/react/docs/rendering-elements.html (一)Element 1.Element是react中最小的构建单元,是一个对象不是DOM,创建的代价比较低. (1)通常我们在代码中使用JSX定义一个Element: const element = <h1>Hello, world</h1>; (2)使用ReactDOM.render来渲染 ReactDOM.render( element, docu

react学习(四)之设置 css样式 篇

react中设置css样式 方法一: 行内样式:使用{{  }},与正常jsx中插入js代码不一样,这里需要两个括号. <div style={ { float: 'right',} }> { this.renderButton() } </div> 样式比较多的话不建议使用该方法. 可以使用方法二 方法二: 在jsx文件中定义样式变量, let buttonStyle = { //定义style变量 backgroundColor: 'blue', float: 'left' a

React组件安装使用和生命周期函数

React安装在使用react时 需要安装 两个模块 react react-dom 初始化时 需要用到react-dom中的render方法 具体如下: import ReactDOM from "react-dom" ReactDOM.render(<div>test</div>,document.getElementById("app"),()=>{ console.log("应用初始化完毕") }) 或者 i

React之生命周期函数

1.新增知识点 /* https://reactjs.org/docs/react-component.html React生命周期函数: 组件加载之前,组件加载完成,以及组件更新数据,组件销毁. 触发的一系列的方法 ,这就是组件的生命周期函数 组件加载的时候触发的函数: 顺序:constructor -> componentWillMount -> render -> componentDidMount 组件数据更新的时候触发的生命周期函数: shouldComponentUpdate

React生命周期函数的使用场景

使用shouldComponentUpdate( ) 生命周期函数,减少render函数的执行,减少对未发生改变的DOM结点的重复渲染. shouldComponentUpdate(nextProps, nextState) { if(nextProps.content !== this.props.content) { return true }else { return false } } render() { console.log('child render') const { cont

react 的生命周期函数

生命周期函数: 是指在某一时刻组件自动执行 的函数 初始化: 设置props和state mounting: componentWillMount 在组件即将被挂载到页面的时候自动执行 render 组件在页面上进行挂载 componentDidMount 在组件被挂载到页面的时候后自动执行 updation:组件更新 props =>componentWillPeceiveProps=>shouldComponentUpdate=> componentWillUpdate=>re

React学习(4)——向服务器请求数据并显示

本文中涉及到的技术包括:node.js/express服务器的搭建.fetch发送数据请求. 在之前的几篇文章中,介绍了如何搭建基础的React项目,以及一些简单知识,现在,我们还需要掌握如何用React来向后台服务器发起HTTP请求,来获取数据.因为一个网站光有静态的页面是不够的,只能称其为静态网站,我们需要获取到数据才能让网页呈现更为丰富的内容. 现在的网站开发一般都采用前后端分离的开发方式.前端人员负责前端页面的实现,后端人员负责提供数据,前端页面将通过访问api接口的方式来链接后台,获取

玩转 React(四)- 创造一个新的 HTML 标签

在第二篇文章 <新型前端开发方式> 中有说到 React 有很爽的一点就是给我们一种创造 HTML 标签的能力,那么今天这篇文章就详细讲解下 React 是如何提供这种能力的,作为前端开发者如何来运用这种能力. 在第三篇文章 <JavaScript代码里写HTML一样可以很优雅> 中介绍了 JavaScript 的扩展语法 JSX,相信大家已经知道了,所谓的创造新的 HTML 的能力,其实就是以极其类似 HTML 的 JSX 语法来使用基于 React 编写的视图层组件.所以说,要