React入门0x008: 生命周期

0x000 概述

上一章说明了生命周期的概念,本质上就是框架在操做组件的过程当中暴露出来的一系列钩子,咱们能够选择咱们须要的钩子,完成咱们本身的业务,如下讲的是react v16.3如下的生命周期,v16.3以及以上的版本有所不一样react

0x001 组件挂载

如下是组件挂载的过程当中触发的声明周期:git

class App extends React.Component {
    constructor(props) {
        super(props)
        console.log('constructor', props)

    }

    componentWillMount() {
        console.log('componentWillMount')
    }

    componentDidMount() {
        console.log('componentDidMount')
    }

    render() {
        console.log('render')
        return <p>{Date()}</p>
    }

    componentDidMount() {
        console.log('componentDidMount')
    }
}

clipboard.png

0x002 组件更新

如下是组件更新的时候触发的生命周期:github

class App extends React.Component {
    constructor() {
        super()
        this.state = {
            date: Date()
        }
        setTimeout(() => {
            this.setState({date: Date()})
        }, 3000)
    }

    componentWillReceiveProps() {
        console.log('componentWillReceiveProps')
    }

    shouldComponentUpdate() {
        console.log('shouldComponentUpdate')
        return true

    }

    render() {
        console.log('render')
        return <p>{this.state.date}</p>
    }

    componentWillUpdate() {
        console.log('componentWillUpdate')

    }

    componentDidUpdate() {
        console.log('componentDidUpdate')

    }

}

第一次的render是由组件挂载引发的,而其余的方法则是由setState引发的
clipboard.png浏览器

0x003 组件卸载

如下是由组件卸载的时候触发的生命周期:性能优化

class Content extends React.Component {
    render(){
        console.log('Content::render')
        return <p>content</p>
    }
    componentWillUnmount() {
        console.log('Content::componentWillUnmount')
    }
}

class App extends React.Component {
    constructor() {
        super()
        this.state = {
            show: true
        }
        setTimeout(() => {
            this.setState({show: false})
        }, 3000)
    }

    render() {
        console.log('App::render')

        return (
            this.state.show
                ? <Content/>
                : null
        )
    }



}

clipboard.png

0x004 完整生命周期

挂载:
constructor
componentWillMount
render
componentDidMount
更新:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
卸载:
componentWillUnmount
错误处理(这里不说):
componentDidCatch

0x005 声明周期使用场景

  1. constructor(props)网络

    该方法主要用来初始化 state,或者初始化一些资源,能够访问 prop,可是访问不了 setState,会报错:Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the App component.
    class App extends React.Component {
        constructor() {
            super()
            this.state = {
                show: true
            }
        }
    
        render() {
            return (
                this.state.show
                    ? <Content/>
                    : null
            )
        }
    
    }
  2. componentWillMount()app

    没啥卵用,能够在这个方法中调用 setState(),而且设置的 state能够在本次渲染生效,推荐使用 constructor
  3. render()框架

    你懂的,每次更新状态都会触发,可是不要在这里调用会触发组件更新的函数,好比 setState(),不然可能陷入无尽阿鼻地狱。
  4. componentDidMount()dom

    这个方法经常使用,触发这个生命周期,意味着 dom和子组件都挂载好了, refs也能够用了,通常在这儿作网络请求。
  5. componentWillReceiveProps(nextProps)函数

    这个组件也经常使用,通常用于父组件状态更新,致使传递给子组件的 props更新,当时子组件又不是直接绑定父组件的 props的时候使用,好比
    class Content extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                content: props.content
            }
        }
    
        render() {
            return this.state.content
        }
    }
    
    class App extends React.Component {
        constructor() {
            super()
            this.state = {
                content: "1"
            }
            setTimeout(() => {
                this.setState({
                    content: 10
                })
            }, 1000)
        }
    
        render() {
            return (
                <Content content={this.state.content}/>
            )
        }
    
    }

    咱们接受父组件的state.content做为子组件的初始化state.content,可是1s 以后,父组件发生了变化,state.content从1变成了10,咱们指望子组件也同时更新,惋惜子组件的constructor只会执行一次,为了解决这个问题,咱们能够添加这个生命周期:

    class Content extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                content: props.content
            }
        }
    
        componentWillReceiveProps(nextProps) {
            this.setState({
                content:nextProps.content
            })
        }
    
        render() {
            return this.state.content
        }
    }

    这样就可已在父组件props更新的时候,触发子组件的更新

  6. shouldComponentUpdate(nextProps, nextState)

    这个组件也很经常使用,用来判断是否要进行某次更新,若是返回 true则执行更新,若是返回 false则不更新,经常使用与性能优化
    class A extends React.Component {
        render() {
            console.log("A::render")
            return "A"
        }
    }
    
    class B extends React.Component {
        render() {
            console.log("B::render")
            return "A"
        }
    }
    
    class App extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                num: 1
            }
            setTimeout(() => {
                this.setState({
                    num: 10,
                    name: 1
                })
            })
        }
    
        render() {
            console.log("App::render")
            return <div>
                    <A name={this.state.name}/>
                    <B name={this.state.name}/>
                <div>
                    {this.state.num}
                </div>
            </div>
        }
    }
    
    ReactDom.render(
        <App></App>,
        document.getElementById('app')
    )

    咱们在App组件中挂载了AB组件,App绑定了state.numAB绑定了state.name,而后在1s 后触发app组件的更新,此时查看浏览器,能够看到,APPAB都执行了render,但其实AB依赖的name并无发生改变。若是是小组件还好,但若是是大组件,那就糟糕了,因此须要避免这种无所谓的更新:

    class A extends React.Component {
        shouldComponentUpdate(nextProps, nextState) {
            return nextProps.name === this.props.name ? true : false
        }
    
        render() {
            console.log("A::render")
            return "A"
        }
    }
    
    class B extends React.Component {
        shouldComponentUpdate(nextProps, nextState) {
            return nextProps.name === this.props.name ? false : true
        }
    
        render() {
            console.log("B::render")
            return "A"
        }
    }

    我在促发这个方法的时候,A组件返回 trueB 组件返回false,查看浏览器,能够发现,触发该方法的时候 A渲染了,而B没有渲染

    clipboard.png

  7. componentWillUpdate(nextProps, nextState)

    没啥卵用,和 componentDidUpdate组成一对儿,若是业务须要,就用
  8. componentDidUpdate()

    没啥卵用,和 componentWillUpdate组成一对儿,若是业务须要,就用
  9. componentWillUnmount

    用于清理资源或者事件
    class Content extends React.Component {
        constructor() {
            super()
            this.state = {
                num: 1
            }
            setInterval(() => {
                this.setState({
                    num: ++this.state.num
                })
                console.log(this.state.num)
            }, 1000)
        }
    
        render() {
            return this.state.num
        }
    }
    
    class App extends React.Component {
        constructor() {
            super()
            this.state = {
                show: true
            }
            setTimeout(() => {
                this.setState({
                    show: false
                })
            },2000)
        }
    
        render() {
            return this.state.show
                ? <Content/>
                : null
        }
    
    }
    
    ReactDom
        .render(
            <App></App>,
            document
                .getElementById(
                    'app'
                )
        )

    咱们在App组件中挂载Content组件,而Content组件则使用定时器每秒更新一次,可是在2s 以后,咱们在App组件中卸载这个组件,可是,查看浏览器能够发现,定时器依旧在工做,而且报错:

clipboard.png

若是咱们返回显示隐藏组件,就会积累愈来愈多的定时器。而后就爆炸了。

```
class Content extends React.Component {
    constructor() {
        super()
        this.state = {
            num: 1
        }
        this.interval=setInterval(() => {
            this.setState({
                num: ++this.state.num
            })
            console.log(this.state.num)
        }, 1000)
    }

    render() {
        return this.state.num
    }
    componentWillUnmount(){
        clearInterval(this.interval)
    }
}
```
这么解决

0x006 总结

在不一样的生命周期作不一样的事。

0x007 资源:

相关文章
相关标签/搜索