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 資源:

相關文章
相關標籤/搜索