上一章說明了生命週期的概念,本質上就是框架在操做組件的過程當中暴露出來的一系列鉤子,咱們能夠選擇咱們須要的鉤子,完成咱們本身的業務,如下講的是react v16.3
如下的生命週期,v16.3
以及以上的版本有所不一樣react
如下是組件掛載的過程當中觸發的聲明週期: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') } }
如下是組件更新的時候觸發的生命週期: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
引發的
瀏覽器
如下是由組件卸載的時候觸發的生命週期:性能優化
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 ) } }
掛載: constructor componentWillMount render componentDidMount 更新: componentWillReceiveProps shouldComponentUpdate componentWillUpdate render componentDidUpdate 卸載: componentWillUnmount 錯誤處理(這裏不說): componentDidCatch
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 tothis.state
directly or define astate = {};
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 ) } }
componentWillMount()
app
沒啥卵用,能夠在這個方法中調用setState()
,而且設置的state
能夠在本次渲染生效,推薦使用constructor
render()
框架
你懂的,每次更新狀態都會觸發,可是不要在這裏調用會觸發組件更新的函數,好比
setState()
,不然可能陷入無盡阿鼻地獄。
componentDidMount()
dom
這個方法經常使用,觸發這個生命週期,意味着dom
和子組件都掛載好了,refs
也能夠用了,通常在這兒作網絡請求。
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
更新的時候,觸發子組件的更新
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
組件中掛載了A
、B
組件,App
綁定了state.num
,A
、B
綁定了state.name
,而後在1s 後觸發app
組件的更新,此時查看瀏覽器,能夠看到,APP
、A
、B
都執行了render
,但其實A
、B
依賴的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
組件返回 true
,B
組件返回false
,查看瀏覽器,能夠發現,觸發該方法的時候 A
渲染了,而B
沒有渲染
componentWillUpdate(nextProps, nextState)
沒啥卵用,和
componentDidUpdate
組成一對兒,若是業務須要,就用
componentDidUpdate()
沒啥卵用,和
componentWillUpdate
組成一對兒,若是業務須要,就用
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
組件中卸載這個組件,可是,查看瀏覽器能夠發現,定時器依舊在工做,而且報錯:
若是咱們返回顯示隱藏組件,就會積累愈來愈多的定時器。而後就爆炸了。 ``` 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) } } ``` 這麼解決
在不一樣的生命週期作不一樣的事。