前端(九):react生命周期

一、组件渲染

  当组件的props或者state发生改变时,组件会自动调用render方法重新渲染。当父组件被重新渲染时,子组件也会被递归渲染。那么组件是如何渲染的呢?

# 方案一
1.state数据
2.JSX模板
3.数据 + 模板 生成真实DOM来显示
4.state发生改变
5.JSX模板
6.数据 + 模板重新结合,生成新的真实的DOM,替换掉以前的DOM
缺陷:
    第一次生成了完整的DOM片段
    第二次生成了完整的DOM片段,替换第一次的DOM片段,比较耗性能
# 方案二
1.state数据
2.JSX模板
3.数据 + 模板 生成真实DOM来显示
4.state发生改变
5.sJSX模板
6.数据 + 模板重新结合,生成新的真实的DOM
7.新的DOM和原来的DOM进行比对,只用新的DOM中改变的部分替换掉以前DOM对应的部分
缺陷:
    因为仍然是生成了一个新的真实的DOM,所以性能提升并不明显
# 方案三
1.state数据
2.JSX模板
3.生成虚拟DOM,也就是一个js对象
    {
        "div": {
            id: "div-id",
            span: {
                id: "span-d",
                class: "span-class",
                content: "hello, world"
            }
        }
    }
4.数据 + 模板 生成真实DOM来显示
    <div id="div-id"><span id="span-id" class="span-class">hello, world</span></div>
5.state发生变化
6.生成新的虚拟DOM
    {
        "div": {
            id: "div-id",
            span: {
                id: "span-d",
                class: "span-class",
                content: "what the hell"
            }
        }
    }
7.对比两个虚拟DOM,将obj中span的content变动更改到原始真实DOM中
    <div id="div-id"><span id="span-id" class="span-class">what the hell</span></div>
优点:
    不再重新创建真实DOM,只是比较两个js对象的不同来修改原始DOM
# 将一个object对象转换成DOM
const dom = {
            "div": {
                id: "div-id",
                span: {
                    id: "span-id",
                    class: "span-class",
                    content: "hello, world"
                }
            }
        };
        function createDom(dom) {
            const div = Object.keys(dom)[0];
            const divNode = document.createElement(div);
            const innerKeys = Object.keys(dom.div);
            for(const i in innerKeys){
                const innerKey = innerKeys[i];
                if(innerKey === "span"){
                    const spanNode = document.createElement(innerKey);
                    const span = dom.div["span"];
                    const spanKeys = Object.keys(span);
                    for (const j in spanKeys){
                        const spanKey = spanKeys[j];
                        if(spanKey === "content"){
                            spanNode.innerText = "hello, world";
                        }else {
                            spanNode.setAttribute(spanKey, span[spanKey]);
                        }
                    }
                    divNode.appendChild(spanNode);
                }else {
                    divNode.setAttribute(innerKey, dom.div[innerKey]);
                }
            }
            return divNode;
        };
        div = createDom(dom);

二、组件的生命周期

  组件的声明周期可分成三个状态:Mounting,已插入真实 DOM;Updating,正在被重新渲染;Unmounting:已移出真实 DOM。如下图所示(本图根据Rosen老师示例改写)。

  

  各个函数的释义(摘自菜鸟教程):

  componentWillMount 在渲染前调用,在客户端也在服务端。

  componentDidMount : 在第一次渲染后调用,只在客户端,只执行一次。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异部操作阻塞UI)。

  componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。

  shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。

shouldComponentUpdate(nextProps, nextState) {    console.log(nextProps, nextState);    console.log(this.props, this.state);    if(this.state.update === true){        // 只有在给定条件发生的时候返回true,也就是可以重新渲染        return true    }   // 只有在给定条件发生的时候返回true,也就是可以重新渲染   if(nextState.update === true){        // 在下一个状态达到条件时重新渲染        return true    }    return false // 其它条件返回false,不重新渲染}

  componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。

  componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。

  componentWillUnmount在组件从 DOM 中移除的时候立刻被调用。

  一个示例:

import React, {Fragment} from "react";

class LifeCircle extends React.Component{
    constructor(props){
        super(props);
        console.log("STEP1: constructor is called.");
        this.state = {
            list: [],
            input: ""
        }
    }
    componentWillMount() {
        console.log("STEP2: componentWillMount is called.");
    }
    componentDidMount() {
        console.log("STEP4: componentDidMount is called."); // 可以在这里写ajax数据请求,因为它只在组件被挂载到页面上时执行一次,而不是render里(因为render会被重复渲染)
    }

    componentWillReceiveProps(nextProps, nextContext) {
        console.log("STEP5: componentWillReceiveProps is called.")
    }

    shouldComponentUpdate(nextProps, nextState, nextContext) {
        console.log("STEP6: shouldComponentUpdate is called.");
        return true; // 是否更新,true更新,更新就是要把有关的子组件也一并渲染;如果子组件没有数据更改那就没重新渲染,此时可以返回一个false
    }
    componentWillUpdate(nextProps, nextState, nextContext) {
        console.log("STEP7: componentWillUpdate is called.")
    }
    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("STEP8: componentDidUpdate is called.")
    }
    componentWillUnmount() {
        console.log("STEP9: componentDidUpdate is called.")
    }

    render() {
        console.log("STEP3: render is called.");
        return (
            <Fragment>
                <div>
                    <input
                        value={this.state.input}
                        onChange={(e) => {this.handleChange(e)}}
                    />
                    <button onClick={() => {this.handleClick()}}>添加句子</button>
                </div>
                <ul>
                    {
                        this.state.list.map((name, index) => {
                            return <li
                                key={index}
                                onClick={() => {this.handleliClick(index)}}
                            > { name }</li>
                        })
                    }
                </ul>
            </Fragment>
        );
    }
    handleChange(e){
        const value = e.target.value;
        this.setState(() => ({
            input: value
        }))
    }
    handleClick(){
        this.setState((prevState)=>({
            list: [...prevState.list, prevState.input],
            input: ""
        }))
    }
    handleliClick(index){
        this.setState((prevState) => {
            const list =[...prevState.list];
            list.splice(index, 1);
            return {
                list
            }
        })
    }
}

export default LifeCircle;

三、使用component请求后台数据并交给组件

  在my-app下建立server/server.js文件,启动一个后端服务:

const express = require(‘express‘);

const app = express();app.get("/data", function (req, res) {    res.json({"name": "old monkey", "age": 5000})});app.listen(3002, function () {    console.log("Node app start at port 3002.")});

  Terminal启动该服务: node server/server.js。此时可以访问http://localhost:3002/data来获取json数据。 

  安装axios: cnpm install axios --save。并在package.json的配置文件中添加"proxy"配置,让它转换端口到3002:

// package.json{  "name": "my-app",  "version": "0.1.0",  "private": true,  "dependencies": {    "axios": "^0.18.0",    "react": "^16.4.1",    "react-dom": "^16.4.1",    "react-scripts": "1.1.4"  },  "scripts": {    "start": "react-scripts start",    "build": "react-scripts build",    "test": "react-scripts test --env=jsdom",    "eject": "react-scripts eject"  },  "proxy": "http://localhost:3002"}

  在src/index.js中写组件:

// src/index.jsimport React from ‘react‘;import ReactDOM from ‘react-dom‘;import axios from ‘axios‘;

class App extends React.Component{    constructor(props){        super(props);        this.state = {name: "monkey", age: 100}

    }  // 在component内部使用ajax请求数据,并通过setState传递给App。    componentDidMount(){        axios.get("/data").then(res=>{            if(res.status === 200){                console.log(res);                this.setState({name: res.data.name, age: res.data.age});            }        }, err=>{            console.log(err);        })    }    addAge(){        this.setState({age: this.state.age + 1})    };    decAge(){        this.setState({age: this.state.age - 1})    }    render (){        const style={            display: "inline-block",            width: "150px",            height: "40px",            backgroundColor: "rgb(173, 173, 173)",            color: "white",            marginRight: "20px"        };        return (            <div>                <h2>this {this.state.name } is { this.state.age } years old.</h2>                <button style={style} onClick={()=>this.addAge()}>增加一岁</button>                <button style={style} onClick={()=>this.decAge()}>减少一岁</button>            </div>        )    }}ReactDOM.render(<App />, document.getElementById(‘root‘));

原文地址:https://www.cnblogs.com/kuaizifeng/p/10158772.html

时间: 2024-10-17 11:58:28

前端(九):react生命周期的相关文章

前端005/React生命周期

ES6中React生命周期 一.React生命周期 React生命周期主要包括三个阶段:初始化阶段.运行中阶段和销毁阶段. 在React不同的生命周期里,会依次触发不同的钩子函数. 二.React的生命周期函数 (一).初始化阶段 1.设置组件的默认属性 static defaultProps = { name: 'sls', age:23 }; //or Counter.defaltProps={name:'sls'} 复制代码 2.设置组件的初始化状态 constructor() { sup

vue与 react 生命周期

Vue vue里的生命周期是什么? vue实例从创建到销毁的过程称之为vue的生命周期 vue的生命周期各阶段都做了什么? beforeCreate 实例创建前:这个阶段实例的data.methods是读不到的created 实例创建后:这个阶段已经完成了数据观测(data observer),属性和方法的运算, watch/event 事件回调.mount挂载阶段还没开始,$el 属性目前不可见,数据并没有在DOM元素上进行渲染beforeMount:在挂载开始之前被调用:相关的 render

react生命周期方法

每一个组件都有几个你可以重写以让代码在处理环节的特定时期运行的"生命周期方法".方法中带有前缀 will 的在特定环节之前被调用,而带有前缀 did 的方法则会在特定环节之后被调用. react生命周期可分为三个状态以及对应的方法 Mounting(装配) constructor() React组件的构造函数将会在装配之前被调用. componentWillMount() 在渲染前调用,在客户端也在服务端. render() 所有组件类都必须有自己的 render 方法,用于输出组件.

vue生命周期和react生命周期对比

一 vue的生命周期如下图所示(很清晰)初始化.编译.更新.销毁 二 vue生命周期的栗子 注意触发vue的created事件以后,this便指向vue实例,这点很重要 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>vue生命周期</title> <script src="../js/vue.js"></

react生命周期知识点

react生命周期知识点 一个React组件的生命周期分为三个部分:实例化.存在期和销毁时. 实例化 组件在客户端被实例化,第一次被创建时,以下方法依次被调用: 1.getDefaultProps2.getInitialState3.componentWillMount4.render5.componentDidMount 当组件在服务端被实例化,首次被创建时,以下方法依次被调用: 1.getDefaultProps2.getInitialState3.componentWillMount4.r

React生命周期学习整理

一.React生命周期 React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁 初始化 1.getDefaultProps() 设置默认的props,也可以用dufaultProps设置组件的默认属性. 2.getInitialState() 在使用es6的class语法时是没有这个钩子函数的,可以直接在constructor中定义this.state.此时可以访问this.props 3.componentWillMount() 组件初始化时只调用,以后组件更新不调用,整个生命周期

react生命周期

1.getDefaultProps 作用于组件类,只调用一次,返回对象用于设置默认的props,对于引用值,会在实例中共享. 2.getInitialState 作用于组件的实例,在实例创建时调用一次,用于初始化每个实例的state,此时可以访问this.props. 3.componentWillMount 在完成首次渲染之前调用,此时仍可以修改组件的state. 4.render 必选的方法,创建虚拟DOM,该方法具有特殊的规则: 只能通过this.props和this.state访问数据

理解React生命周期的好例子

class App extends React.Component { static propTypes = { }; static defaultProps = { }; constructor(props) { super(props); this.state = { data: 0 }; } componentWillUnMount() { } componentWillReceiveProps(nextProps) { } shouldComponentUpdate(nextProps,

react生命周期总结

当通过createClass创建了组件之后,该React组件就有了生命周期.通常一个React组件的生命周期可分为三个阶段: Mounting:挂载组件,也就是组件实例化 ReciveProps:存在期,在这个时期组件的props和state会变化,重新渲染组件 Unmounting:卸载组件,也就是组件被销毁 React在生命周期中提供了10种API: 1.getDefaultProps():作用于组件类,只调用一次,返回对象用于设置默认的props,对于引用值,会在实例中共享. 2.getI