溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

react生命周期是什么

發布時間:2020-12-02 11:03:46 來源:億速云 閱讀:234 作者:小新 欄目:web開發

了解react生命周期是什么?這個問題可能是我們日常學習或工作經常見到的。希望通過這個問題能讓你收獲頗深。下面是小編給大家帶來的參考內容,讓我們一起來看看吧!

一個React組件的生命周期分為三個部分:實例化、存在期和銷毀時。

實例化階段

客戶端渲染時,如下依次被調用

  • getDefaultProps()
  • getInitialState()
  • componentWillMount()
  • render()
  • componentDidMount()

服務端渲染

  • getDefaultProps()
  • getInitialState()
  • componentWillMount()
  • render()

注意:componentDidMount()不會再服務端被渲染;

getDefaultProps

對于每個組件實例來講,這個方法只會調用一次,該組件類的所有后續應用,getDefaultPops 將不會再被調用,其返回的對象可以用于設置默認的props值。

var Hello = React.creatClass({
    getDefaultProps: function(){
        return {
            name: 'pomy',
            git: 'dwqs'
        }
    },
    
    render: function(){
        return (
            <p>Hello,{this.props.name},git username is {this.props.dwqs}</p>
        )
    }
});

ReactDOM.render(<Hello />, document.body);

也可以在掛載組件的時候設置 props。

var data = [{title: 'Hello'}];
<Hello data={data} />

或者調用 setProps (一般不需要調用)來設置其 props

var data = [{title: 'Hello'}];
var Hello = React.render(<Demo />, document.body);
Hello.setProps({data:data});

但只能在子組件或組件樹上調用 setProps。別調用 this.setProps 或者 直接修改 this.props。將其當做只讀數據。

React通過 propTypes 提供了一種驗證 props 的方式,propTypes 是一個配置對象,用于定義屬性類型:

var survey = React.createClass({
    propTypes: {
        survey: React.PropTypes.shape({
            id: React.PropTypes.number.isRequired
        }).isRequired,
        onClick: React.PropTypes.func,
        name: React.PropTypes.string,
        score: React.PropTypes.array
        ...
    },
    
    //...
})

或者

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class BetterImage extends Component{...}

BetterImage.PropTypes={
  src: PropTypes.string,
  center: PropTypes.bool,
  loadingImage: PropTypes.string,
  defaultImage: PropTypes.string,
  onLoad: PropTypes.func,
  onError: PropTypes.func,
  onComplete: PropTypes.func
}
BetterImage.defaultProps={
  ....
}

getInitialState

對于組件的每個實例來說,這個方法的調用有且只有一次,用來初始化每個實例的 state,在這個方法里,可以訪問組件的 props。每一個React組件都有自己的 state,其與 props 的區別在于 state只存在組件的內部,props 在所有實例中共享。

getInitialState 和 getDefaultPops 的調用是有區別的,getDefaultPops 是對于組件類來說只調用一次,后續該類的應用都不會被調用,而 getInitialState 是對于每個組件實例來講都會調用,并且只調一次。

var LikeButton = React.createClass({
  //初始化State
  getInitialState: function() {
    return {liked: false};
  },
  
  handleClick: function(event) {
    //設置修改State
    this.setState({liked: !this.state.liked});
  },

  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);

每次修改 state,都會重新渲染組件,實例化后通過 state 更新組件,會依次調用下列方法:

1、shouldComponentUpdate
2、componentWillUpdate
3、render
4、componentDidUpdate
  • componentWillMount

在渲染前調用,在客戶端也在服務端。React 官方正式發布了 v16.3 版本。在這次的更新中,除了前段時間被熱烈討論的新 Context API 之外,新引入的兩個生命周期函數 getDerivedStateFromProps,getSnapshotBeforeUpdate 以及在未來 v17.0 版本中即將被移除的三個生命周期函數 componentWillMount,componentWillReceiveProps,componentWillUpdate .

在這個生命周期中你會遇到一下問題:

a.首屏無數據導致白屏
  在 React 應用中,許多開發者為了避免第一次渲染時頁面因為沒有獲取到異步數據導致的白屏,而將數據請求部分的代碼放在了 componentWillMount 中,希望可以避免白屏并提早異步請求的發送時間。但事實上在 componentWillMount 執行后,第一次渲染就已經開始了,所以如果在 componentWillMount 執行時還沒有獲取到異步數據的話,頁面首次渲染時也仍然會處于沒有異步數據的狀態。換句話說,組件在首次渲染時總是會處于沒有異步數據的狀態,所以不論在哪里發送數據請求,都無法直接解決這一問題。而關于提早發送數據請求,官方也鼓勵將數據請求部分的代碼放在組件的 constructor 中,而不是 componentWillMount。
 若是為了改善用戶體驗曾經用過的解決方法有兩個:

方法一:異步請求組件,使用nprogress 添加加載動畫;

import React, { Component } from 'react'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import './customNprogress.styl'

NProgress.configure({ showSpinner: false })

export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    state = {
      component: null
    }

    async componentDidMount() {
      NProgress.start()
      const { default: component } = await importComponent()
      NProgress.done()

      this.setState({ component })
    }

    render() {
      const C = this.state.component

      return C ? <C {...this.props} /> : null
    }
  }

  return AsyncComponent
}

const AsyncNotFound = asyncComponent(() => import(/* webpackChunkName: "NotFound" */ '@/routes/NotFound'))

方法二:使用  onreadystatechange  去監聽 readyState,在資源加載完成之前加載一個只有框架的靜態頁面,頁面不請求數據。當數據請求完成之后再將路由切換到真實的首頁。

  function listen () {
    if (document.readyState == 'complete') { // 資源加載完成
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={Index}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    } else { // 資源加載中
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={FirstScreen}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    }
}

document.onreadystatechange = listen

具體參考解決React首屏加載白屏的問題

b.事件訂閱

另一個常見的用例是在 componentWillMount 中訂閱事件,并在 componentWillUnmount 中取消掉相應的事件訂閱。但事實上 React 并不能夠保證在 componentWillMount 被調用后,同一組件的 componentWillUnmount 也一定會被調用。一個當前版本的例子如服務端渲染時,componentWillUnmount 是不會在服務端被調用的,所以在 componentWillMount 中訂閱事件就會直接導致服務端的內存泄漏。另一方面,在未來 React 開啟異步渲染模式后,在 componentWillMount 被調用之后,組件的渲染也很有可能會被其他的事務所打斷,導致 componentWillUnmount 不會被調用。而 **componentDidMount 就不存在這個問題,在 componentDidMount 被調用后,componentWillUnmount 一定會隨后被調用到,并根據具體代碼清除掉組件中存在的事件訂閱。**

render

該方法會創建一個虛擬DOM,用來表示組件的輸出。對于一個組件來講,render方法是唯一一個必需的方法。render方法需要滿足下面幾點:

  • 只能通過 this.props 和 this.state 訪問數據(不能修改)
  • 可以返回 null,false(這種場景下,react渲染一個<noscript>標簽,當返回null或者false時,ReactDOM.findDOMNode(this)返回null) 或者任何React組件
  • 只能出現一個頂級組件,不能返回一組元素
  • 不能改變組件的狀態
  • 不能修改DOM的輸出

render方法返回的結果并不是真正的DOM元素,而是一個虛擬的表現,類似于一個DOM tree的結構的對象。react之所以效率高,就是這個原因。

render執行情況如下:

1. 首次加載
2. setState改變組件內部state。
   注意: 此處是說通過setState方法改變。
3. 接受到新的props

注意:因為數據是異步的情況,會導致組件重復渲染

componentDidMount

該方法不會在服務端被渲染的過程中調用。該方法被調用時,已經渲染出真實的 DOM,可以再該方法中通過 this.getDOMNode() 訪問到真實的 DOM(推薦使用 ReactDOM.findDOMNode())。

var data = [..];
var comp = React.createClass({
    render: function(){
        return <imput .. />
    },
    componentDidMount: function(){
        $(this.getDOMNode()).autoComplete({
            src: data
        })
    }
})

由于組件并不是真實的 DOM 節點,而是存在于內存之中的一種數據結構,叫做虛擬 DOM (virtual DOM)。只有當它插入文檔以后,才會變成真實的 DOM 。有時需要從組件獲取真實 DOM 的節點,這時就要用到 ref 屬性:

var Area = React.createClass({
    render: function(){
        this.getDOMNode(); //render調用時,組件未掛載,這里將報錯
        
        return <canvas ref='mainCanvas'>
    },
    componentDidMount: function(){
        var canvas = this.refs.mainCanvas.getDOMNode();
        //這是有效的,可以訪問到 Canvas 節點
    }
})

需要注意的是,由于 this.refs.[refName] 屬性獲取的是真實 DOM ,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個屬性,否則會報錯。如果ref回調函數以inline函數的方式來指定,那么在組件更新的時候ref回調會被調用2次。第一次回調的時候傳入的參數是null,而第二次的時候才真正的傳入DOM節點

更多了解ref使用
從React官方文檔看 refs 的使用和未來
獲取真實dom,并獲取dom css 三種方法

存在期

此時組件已經渲染好并且用戶可以與它進行交互,比如鼠標點擊,手指點按,或者其它的一些事件,導致應用狀態的改變,你將會看到下面的方法依次被調用;

  1. componentWillReceiveProps()
  2. shouldComponentUpdate()
  3. componentWillUpdate()
  4. render()
  5. componentDidUpdate()

componentWillReceiveProps

當props發生變化時執行,初始化render時不執行,在這個回調函數里面,你可以根據屬性的變化,通過調用this.setState()來更新你的組件狀態,舊的屬性還是可以通過this.props來獲取,這里調用更新狀態是安全的,并不會觸發額外的render調用。

componentWillReceiveProps: function(nextProps){
    if(nextProps.checked !== undefined){
        this.setState({
            checked: nextProps.checked
        })
    }
}

了解更多點擊此處

shouldComponentUpdate

shouldComponentUpdate函數是重渲染時render()函數調用前被調用的函數,它接受兩個參數:nextProps和nextState,分別表示下一個props和下一個state的值。并且,當函數返回false時候,阻止接下來的render()函數及后面的 componentWillUpdate,componentDidUpdate 方法的調用,阻止組件重渲染,而返回true時,組件照常重渲染。

了解更多點擊此處--真的講的好

componentWillUpdate

這個方法和 componentWillMount 類似,在組件接收到了新的 props 或者 state 即將進行重新渲染前,componentWillUpdate(object nextProps, object nextState) 會被調用,注意不要在此方面里再去更新 props 或者 state。

componentDidUpdate

這個方法和 componentDidMount 類似,在組件重新被渲染之后,componentDidUpdate(object prevProps, object prevState) 會被調用??梢栽谶@里訪問并修改 DOM。

銷毀

componentWillUnmount

每當React使用完一個組件,這個組件必須從 DOM 中卸載后被銷毀,此時 componentWillUnmout 會被執行,完成所有的清理和銷毀工作,在 componentDidMount 中添加的任務都需要再該方法中撤銷,如創建的定時器或事件監聽器。

當再次裝載組件時,以下方法會被依次調用:

1、getInitialState
2、componentWillMount
3、render
4、componentDidMount

React v.16生命周期

constructor(props) // 初始化參數

componentWillMount()

render() // 第一次渲染 

componentDidMount()

**當父組件向子組件傳入props發生改變后,依次調用**

componentWillReceiveProps(nextProps)

shouldComponentUpdate(nextProps, nextState) 

componentWillUpdate()

render() //子組件更新渲染

componentDidUpdate()

**當組件自身state發生變化后**

componentWillUpdate()

render() //組件再次更新渲染

componentDidUpdate()


當組件卸載

componentWillUnmount()

與低于React16版本的比較

  1. React16新的生命周期棄用了componentWillMount、componentWillReceiveProps,componentWillUpdate
  2. 新增了getDerivedStateFromProps、getSnapshotBeforeUpdate來代替棄用的三個鉤子函數(componentWillMount、componentWillReceivePorps,componentWillUpdate)
  3. React16并沒有刪除這三個鉤子函數,但是不能和新增的鉤子函數(getDerivedStateFromProps、getSnapshotBeforeUpdate)混用,React17將會刪除componentWillMount、componentWillReceivePorps,componentWillUpdate
  4. 新增了對錯誤的處理(componentDidCatch)

感謝各位的閱讀!看完上述內容,你們對react生命周期是什么大概了解了嗎?希望文章內容對大家有所幫助。如果想了解更多相關文章內容,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女