React学习笔记—生命周期

React中的生命周期

React中的生命周期

一、Reac生命周期初始化阶段

1、UNSAFE_componentWillMount ==> 挂载之前

render 之前最后一次修改状态的机会
使用 componentWillMount 会报警告,建议使用 UNSAFE_componentWillMount

2、render ==> 渲染页面

只能访问 this.propsthis.state,不允许修改状态和 DOM 输出

3、componentDidMount ==> 挂载完成

成功 render 并渲染完成真实 DOM 之后触发,可以修改 DOM,一般 Ajax 请求会在这里发送

4、初始化阶段例子:

// 16.2 版本之前 - 老的生命周期
// 16.2 版本之后 - 删了之前三个生命周期,换成了 两个新的生命周期

import React, { Component } from 'react'

export default class App extends Component {

    state = {
        dataList: []
    }

    // 挂载之前
    UNSAFE_componentWillMount() {
        console.log("componentWillMount", "ajax", "setInterval");
    }

    // 挂载完成
    componentDidMount() {
        console.log("componentDidMount", "ajax,绑定事件,setInterval");
        fetch("/deskComputer.json").then(res => res.json()).then(res => {
            console.log(res);
            this.setState({
                dataList: res.body.detail
            })
        })
    }

    // 渲染页面
    render() {
        console.log("render");
        return (
            <div>
                {
                    this.state.dataList.map(item =>
                        <li key={item.id}>{item.id}---{item.title}</li>
                    )
                }
            </div>
        )
    }
}

二、React生命周期运行(更新)阶段

1、 UNSAFE_componentWillReceiveProps ==> 组件将收到更新的数据

父组件修改属性触发(只要调用 setState 就会执行),根据 id 请求数据的时候,可以在这个生命周期里请求

使用 componentWillReceiveProps 会报警告,建议使用 UNSAFE_componentWillReceiveProps

import React, { Component } from 'react'

class Child extends Component {
    componentDidMount() {
        console.log("获取ajax数据", this.props.myname);
    }
    // 组件将要得到属性的时候(父传子)
    UNSAFE_componentWillReceiveProps(nextProps) {
        console.log("获取ajax数据", "componentWillReceiveProps"); // 根据id请求数据的时候,可以在这个生命周期里请求
        console.log("componentWillReceiveProps", nextProps.myname); // 只要调用setState就会执行
    }

    render() {
        return (
            <div>
                child组件
                {this.props.myname}
            </div>
        )
    }
}

export default class App extends Component {
    state = {
        myname: "4321"
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                    this.setState({
                        myname: "2345"
                    })
                }}>click</button>
                <Child myname={this.state.myname}></Child>
            </div>
        )
    }
}

2、shouldComponentUpdate ==> 性能调优函数

返回 false 会阻止 render 调用
shouldComponentUpdate 为性能调优函数,控制组件自身或者子组件是否需要更新
新的状态和老的状态做对比,用于重复更新做对比,如果更改的数据与原数据一样,就不做更新

3、UNSAFE_componentWillUpdate ==> 更新之前

不能修改属性和状态
使用 componentWillUpdate 会报警告,建议使用 UNSAFE_componentWillUpdate

4、render ==> 渲染页面

只能访问 this.propsthis.state,不允许修改状态和 DOM 输出

5、componentDidUpdate ==> 更新完成

可以修改 DOM

6、更新阶段例子:

import React, { Component } from 'react'

export default class App extends Component {

    state = {
        myname: "liutao"
    }

    // 将要更新
    UNSAFE_componentWillUpdate() {
        console.log("componentWillUpdate");
    }

    // 更新完成
    componentDidUpdate(prevProps, prevState) {
        console.log("componentDidUpdate");
    }

    shouldComponentUpdate(nextProps, nextState) {
        // 性能调优函数 
        // 新的状态和老的状态做对比
        // 用于重复更新做对比,如果更改的数据与原数据一样,就不做更新
        console.log("shouldComponentUpdate", this.state.myname);
        if (this.state.myname !== nextState.myname) {
            return true
        } else {
            return false
        }
    }

    // 组件将要得到属性的时候(父传子)
    UNSAFE_componentWillReceiveProps() {
        console.log("componentWillReceiveProps");
    }



    // 正在更新
    render() {
        console.log("render");

        return (
            <div>
                {this.state.myname}
                <button onClick={() => {
                    this.setState({
                        myname: "xiaoming"
                    }) // setState  开启更新, 虚拟dom 创建,diff算法对比,补丁更新
                }}>click</button>
            </div>
        )
    }
}

三、React生命周期销毁阶段

1、componentWillUnmount ==> 销毁阶段

在删除组件之前进行清理操作,比如计时器和事件监听等操作

每次销毁都会走这个生命周期

import React, { Component } from 'react'


class Navbar extends Component {
    render() {
        return (
            <div style={{ background: "red" }}>
                Navbar---
                <button onClick={this.handleClick}>click</button>
            </div>
        )
    }
    handleClick = () => {
        this.props.onKerwinEvent()
    }
}

class Sidebar extends Component {
    render() {
        return (
            <div style={{ background: "yellow" }}>
                Sidebar
                <ul>
                    <li>1111</li>
                    <li>222222</li>
                    <li>111333331</li>
                </ul>
            </div>
        )
    }
    componentWillUnmount() {
        console.log("componentWillUnmount", "clearInterval", "window.onscroll=null");

}
export default class App extends Component {
    state = {
        isShow: true
    }
    render() {
        return (
            <div>
                <Navbar onKerwinEvent={() => {
                    console.log(1111111);
                    this.setState({
                        isShow: !this.state.isShow
                    })
                }}></Navbar>
                {
                    this.state.isShow ?
                        <Sidebar></Sidebar> : null
                }
            </div>
        )
    }
}

四、React生命周期中存在的问题

1、componentWillMount ==> 挂载之前的问题

ssr(服务端渲染)中这个方法将会被多次调用, 所以会重复触发多遍,同时在这里如果绑定事件, 将无法解绑,导致内存泄漏 , 变得不够安全高效逐步废弃

2、componentWillReceiveProps ==> 更新中的问题

更新前记录 DOM 状态, 可能会做一些处理,与 componentDidUpdate 相隔时间如果过长, 会导致状态不太信

3、componetWillupdate ==> 更新之前的问题

componetWillupdate , 更新前记录 DOM 状态, 可能会做一些处理,与 componentDidUpdate 相隔时间如果过长,会导致 状态不太信 (邮件处理)


五、React生命周期中问题的解决方法(新的两个生命周期)

1、getDerivedStateFromProps ==> 从props中获取state

getDerivedStateFromProps 第一次的初始化组件以及后续的更新过程中(包括自身状态更新以及父传子) ,返回一个对象作为新的 state,返回 null 则说明不需要在这里更新 state
在静态函数中没有 this,但是有个参数 state 可以访问到定义的参数
这个方法不支持异步,所以不能发送 Ajax 请求,需要在 componentDidUpdate 生命周期里做 Ajax 请求

2、getDerivedStateFromProps的异步和同步方法

getDerivedStateFromProps同步解决方案:

import React, { Component } from 'react'

class Child extends Component {
    state = {
        myname: "kerwin"
    }

    // 在静态函数中没有this,但是有个参数state可以访问到定义的参数
    static getDerivedStateFromProps(nextProps, state) {
        document.title = nextProps.myid
        return {
            myname: state.myname.substring(0, 1).toUpperCase() + state.myname.substring(1)
        }
    }

    // static getDerivedStateFromProps(nextProps) {
    //     document.title = nextProps.myid
    //     return null

    // }

    render() {
        return (
            <div>App---{this.props.myid}--{this.state.myname}</div>
        )
    }
}

export default class App extends Component {
    state = {
        myid: 0
    }
    render() {
        return (
            <div>
                <ul>
                    <li onClick={() => {
                        this.setState({
                            myid: 0
                        })
                    }}>衣服</li>
                    <li onClick={() => {
                        this.setState({
                            myid: 1
                        })
                    }}>裤子</li>
                    <li onClick={() => {
                        this.setState({
                            myid: 2
                        })
                    }}>鞋子</li>
                </ul>
                <Child myid={this.state.myid}></Child>
            </div>
        )
    }
}

getDerivedStateFromProps异步解决方案:

import React, { Component } from 'react'

class List extends Component {
    // componentDidMount() {
    //     console.log("componentDidMount,发ajax请求");
    // }

    // componentWillReceiveProps(nextProps) {
    //     console.log("componentWillReceiveProps", nextProps.id);

    // }
    state = {
        myid: 0,
        mytext: "11111111"
    }

    // 第一次渲染会执行,每次更新也会执行
    // 这个方法不支持异步,所以不能发送Ajax请求,需要在componentDidUpdate生命周期里做Ajax请求
    // 只触发一次更新,所以解决了多次更新请求Ajax的问题
    static getDerivedStateFromProps(nextProps) {
        console.log(nextProps);
        return {
            myid: "/maizuo" + nextProps.id
        }
    }

    render() {
        return (
            <div>
                {this.props.id}---{this.state.myid}
            </div>
        )
    }

    // 每次更新在这里发Ajax请求
    componentDidUpdate() {
        console.log("发ajax请求", this.state.myid);

    }
}

export default class App extends Component {
    state = {
        id: 0
    }

    render() {
        return (
            <div>
                <ul>
                    <li onClick={() => {
                        this.setState({
                            id: 0
                        })
                    }}>衣服</li>
                    <li onClick={() => {
                        this.setState({
                            id: 1
                        })
                    }}>裤子</li>
                    <li onClick={() => {
                        this.setState({
                            id: 2
                        })
                    }}>鞋子</li>
                </ul>
                <List id={this.state.id}></List>
            </div>
        )
    }
}

3、getSnapshotBeforeUpdate ==> 更新前获取快照

getSnapshotBeforeUpdate 取代了 componetWillUpdate ,触发时间为 update 发生的时候,在 render之后 dom 渲染之前返回一个值,作为 componentDidUpdate 的第三个参数。

getSnapshotBeforeUpdate解决方案:

import React, { Component } from 'react'

export default class App extends Component {
    state = {
        myname: "liutao"
    }
    render() {
        console.log("render");

        return (
            <div>
                <div>{this.state.myname}</div>
                <button onClick={() => {
                    this.setState({
                        myname: "xiaoming"
                    })
                }}>click</button>
            </div>
        )
    }

    // UNSAFE_componentWillUpdate() {
    //     console.log("componentWillUpdate");

    // }


    getSnapshotBeforeUpdate = (prevProps, prevState) => {
        console.log("getSnapshotBeforeUpdate");
        return {
            y: 10
        }
    }

    componentDidUpdate(prevProps, prevState, data) {
        console.log("componentDidUpdate", data);
    }
}

六、React中性能优化的方案

1、使用shouldComponentUpdate:

控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下, 需要进行优化

import React, { Component } from 'react'

export default class App extends Component {

    state = {
        myname: "liutao"
    }

    // 将要更新
    UNSAFE_componentWillUpdate() {
        console.log("componentWillUpdate");
    }

    // 更新完成
    componentDidUpdate(prevProps, prevState) {
        console.log("componentDidUpdate");
    }

    shouldComponentUpdate(nextProps, nextState) {
        // 性能调优函数 
        // 新的状态和老的状态做对比
        // 用于重复更新做对比,如果更改的数据与原数据一样,就不做更新
        console.log("shouldComponentUpdate", this.state.myname);
        if (this.state.myname !== nextState.myname) {
            return true
        } else {
            return false
        }
    }

    // 组件将要得到属性的时候(父传子)
    UNSAFE_componentWillReceiveProps() {
        console.log("componentWillReceiveProps");
    }



    // 正在更新
    render() {
        console.log("render");

        return (
            <div>
                {this.state.myname}
                <button onClick={() => {
                    this.setState({
                        myname: "xiaoming"
                    }) // setState  开启更新, 虚拟dom 创建,diff算法对比,补丁更新
                }}>click</button>
            </div>
        )
    }
}

2、使用PureComponent:

PureComponent *会帮你比较新 *props 跟旧的 props, 新的 state *和老的 *state(值相等,或者对象含有相同的属性、且属性值相等 ),决定 shouldcomponentUpdate 返回 true 或者 false, 从而决定要不要呼叫 render function *。 注意: 如果你的 *stateprops 『永远都会变』,那 PureComponent 并不会比较 快,因为 shallowEqual 也需要花时间(例如倒计时,每次都需要更新)

import React, { PureComponent } from 'react'

export default class App extends PureComponent {
    state = {
        myname: "liutao"
    }
    // 将要更新
    UNSAFE_componentWillUpdate() {
        console.log("componentWillUpdate");
    }

    // 更新完成
    componentDidUpdate(prevProps, prevState) {
        console.log("componentDidUpdate");
    }

    // shouldComponentUpdate(nextProps, nextState) {
    //     // 性能调优函数 
    //     // 新的状态和老的状态做对比
    //     // 用于重复更新做对比,如果更改的数据与原数据一样,就不做更新
    //     console.log("shouldComponentUpdate", this.state.myname);
    //     if (this.state.myname !== nextState.myname) {
    //         return true
    //     } else {
    //         return false
    //     }
    // }

    // 组件将要得到属性的时候(父传子)
    UNSAFE_componentWillReceiveProps() {
        console.log("componentWillReceiveProps");
    }

    // 正在更新
    render() {
        console.log("render");

        return (
            <div>
                {this.state.myname}
                <button onClick={() => {
                    this.setState({
                        myname: "xiaoming"
                    }) // setState  开启更新, 虚拟dom 创建,diff算法对比,补丁更新
                }}>click</button>
            </div>
        )
    }
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 848130454@qq.com

文章标题:React学习笔记—生命周期

文章字数:2.7k

本文作者:Spicy boy

发布时间:2020-04-25, 00:06:20

最后更新:2020-08-26, 13:06:10

原始链接:http://www.spicyboy.cn/2020/04/25/React%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E2%80%94%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏