您好,登錄后才能下訂單哦!
了解react生命周期是什么?這個(gè)問題可能是我們?nèi)粘W(xué)習(xí)或工作經(jīng)常見到的。希望通過這個(gè)問題能讓你收獲頗深。下面是小編給大家?guī)淼膮⒖純?nèi)容,讓我們一起來看看吧!
一個(gè)React組件的生命周期分為三個(gè)部分:實(shí)例化、存在期和銷毀時(shí)。
客戶端渲染時(shí),如下依次被調(diào)用
服務(wù)端渲染
注意:componentDidMount()不會(huì)再服務(wù)端被渲染;
getDefaultProps
對(duì)于每個(gè)組件實(shí)例來講,這個(gè)方法只會(huì)調(diào)用一次,該組件類的所有后續(xù)應(yīng)用,getDefaultPops 將不會(huì)再被調(diào)用,其返回的對(duì)象可以用于設(shè)置默認(rèn)的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);
也可以在掛載組件的時(shí)候設(shè)置 props。
var data = [{title: 'Hello'}]; <Hello data={data} />
或者調(diào)用 setProps (一般不需要調(diào)用)來設(shè)置其 props
var data = [{title: 'Hello'}]; var Hello = React.render(<Demo />, document.body); Hello.setProps({data:data});
但只能在子組件或組件樹上調(diào)用 setProps。別調(diào)用 this.setProps 或者 直接修改 this.props。將其當(dāng)做只讀數(shù)據(jù)。
React通過 propTypes 提供了一種驗(yàn)證 props 的方式,propTypes 是一個(gè)配置對(duì)象,用于定義屬性類型:
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
對(duì)于組件的每個(gè)實(shí)例來說,這個(gè)方法的調(diào)用有且只有一次,用來初始化每個(gè)實(shí)例的 state,在這個(gè)方法里,可以訪問組件的 props。每一個(gè)React組件都有自己的 state,其與 props 的區(qū)別在于 state只存在組件的內(nèi)部,props 在所有實(shí)例中共享。
getInitialState 和 getDefaultPops 的調(diào)用是有區(qū)別的,getDefaultPops 是對(duì)于組件類來說只調(diào)用一次,后續(xù)該類的應(yīng)用都不會(huì)被調(diào)用,而 getInitialState 是對(duì)于每個(gè)組件實(shí)例來講都會(huì)調(diào)用,并且只調(diào)一次。
var LikeButton = React.createClass({ //初始化State getInitialState: function() { return {liked: false}; }, handleClick: function(event) { //設(shè)置修改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,都會(huì)重新渲染組件,實(shí)例化后通過 state 更新組件,會(huì)依次調(diào)用下列方法:
1、shouldComponentUpdate 2、componentWillUpdate 3、render 4、componentDidUpdate
在渲染前調(diào)用,在客戶端也在服務(wù)端。React 官方正式發(fā)布了 v16.3 版本。在這次的更新中,除了前段時(shí)間被熱烈討論的新 Context API 之外,新引入的兩個(gè)生命周期函數(shù) getDerivedStateFromProps,getSnapshotBeforeUpdate 以及在未來 v17.0 版本中即將被移除的三個(gè)生命周期函數(shù) componentWillMount,componentWillReceiveProps,componentWillUpdate .
在這個(gè)生命周期中你會(huì)遇到一下問題:
a.首屏無數(shù)據(jù)導(dǎo)致白屏
在 React 應(yīng)用中,許多開發(fā)者為了避免第一次渲染時(shí)頁面因?yàn)闆]有獲取到異步數(shù)據(jù)導(dǎo)致的白屏,而將數(shù)據(jù)請(qǐng)求部分的代碼放在了 componentWillMount 中,希望可以避免白屏并提早異步請(qǐng)求的發(fā)送時(shí)間。但事實(shí)上在 componentWillMount 執(zhí)行后,第一次渲染就已經(jīng)開始了,所以如果在 componentWillMount 執(zhí)行時(shí)還沒有獲取到異步數(shù)據(jù)的話,頁面首次渲染時(shí)也仍然會(huì)處于沒有異步數(shù)據(jù)的狀態(tài)。換句話說,組件在首次渲染時(shí)總是會(huì)處于沒有異步數(shù)據(jù)的狀態(tài),所以不論在哪里發(fā)送數(shù)據(jù)請(qǐng)求,都無法直接解決這一問題。而關(guān)于提早發(fā)送數(shù)據(jù)請(qǐng)求,官方也鼓勵(lì)將數(shù)據(jù)請(qǐng)求部分的代碼放在組件的 constructor 中,而不是 componentWillMount。
若是為了改善用戶體驗(yàn)曾經(jīng)用過的解決方法有兩個(gè):
方法一:異步請(qǐng)求組件,使用nprogress 添加加載動(dòng)畫;
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 去監(jiān)聽 readyState,在資源加載完成之前加載一個(gè)只有框架的靜態(tài)頁面,頁面不請(qǐng)求數(shù)據(jù)。當(dāng)數(shù)據(jù)請(qǐng)求完成之后再將路由切換到真實(shí)的首頁。
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.事件訂閱
另一個(gè)常見的用例是在 componentWillMount 中訂閱事件,并在 componentWillUnmount 中取消掉相應(yīng)的事件訂閱。但事實(shí)上 React 并不能夠保證在 componentWillMount 被調(diào)用后,同一組件的 componentWillUnmount 也一定會(huì)被調(diào)用。一個(gè)當(dāng)前版本的例子如服務(wù)端渲染時(shí),componentWillUnmount 是不會(huì)在服務(wù)端被調(diào)用的,所以在 componentWillMount 中訂閱事件就會(huì)直接導(dǎo)致服務(wù)端的內(nèi)存泄漏。另一方面,在未來 React 開啟異步渲染模式后,在 componentWillMount 被調(diào)用之后,組件的渲染也很有可能會(huì)被其他的事務(wù)所打斷,導(dǎo)致 componentWillUnmount 不會(huì)被調(diào)用。而 **componentDidMount 就不存在這個(gè)問題,在 componentDidMount 被調(diào)用后,componentWillUnmount 一定會(huì)隨后被調(diào)用到,并根據(jù)具體代碼清除掉組件中存在的事件訂閱。**
render
該方法會(huì)創(chuàng)建一個(gè)虛擬DOM,用來表示組件的輸出。對(duì)于一個(gè)組件來講,render方法是唯一一個(gè)必需的方法。render方法需要滿足下面幾點(diǎn):
render方法返回的結(jié)果并不是真正的DOM元素,而是一個(gè)虛擬的表現(xiàn),類似于一個(gè)DOM tree的結(jié)構(gòu)的對(duì)象。react之所以效率高,就是這個(gè)原因。
render執(zhí)行情況如下:
1. 首次加載
2. setState改變組件內(nèi)部state。
注意: 此處是說通過setState方法改變。
3. 接受到新的props
注意:因?yàn)閿?shù)據(jù)是異步的情況,會(huì)導(dǎo)致組件重復(fù)渲染
componentDidMount
該方法不會(huì)在服務(wù)端被渲染的過程中調(diào)用。該方法被調(diào)用時(shí),已經(jīng)渲染出真實(shí)的 DOM,可以再該方法中通過 this.getDOMNode() 訪問到真實(shí)的 DOM(推薦使用 ReactDOM.findDOMNode())。
var data = [..]; var comp = React.createClass({ render: function(){ return <imput .. /> }, componentDidMount: function(){ $(this.getDOMNode()).autoComplete({ src: data }) } })
由于組件并不是真實(shí)的 DOM 節(jié)點(diǎn),而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu),叫做虛擬 DOM (virtual DOM)。只有當(dāng)它插入文檔以后,才會(huì)變成真實(shí)的 DOM 。有時(shí)需要從組件獲取真實(shí) DOM 的節(jié)點(diǎn),這時(shí)就要用到 ref 屬性:
var Area = React.createClass({ render: function(){ this.getDOMNode(); //render調(diào)用時(shí),組件未掛載,這里將報(bào)錯(cuò) return <canvas ref='mainCanvas'> }, componentDidMount: function(){ var canvas = this.refs.mainCanvas.getDOMNode(); //這是有效的,可以訪問到 Canvas 節(jié)點(diǎn) } })
需要注意的是,由于 this.refs.[refName] 屬性獲取的是真實(shí) DOM ,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個(gè)屬性,否則會(huì)報(bào)錯(cuò)。如果ref回調(diào)函數(shù)以inline函數(shù)的方式來指定,那么在組件更新的時(shí)候ref回調(diào)會(huì)被調(diào)用2次。第一次回調(diào)的時(shí)候傳入的參數(shù)是null,而第二次的時(shí)候才真正的傳入DOM節(jié)點(diǎn)
更多了解ref使用
從React官方文檔看 refs 的使用和未來
獲取真實(shí)dom,并獲取dom css 三種方法
此時(shí)組件已經(jīng)渲染好并且用戶可以與它進(jìn)行交互,比如鼠標(biāo)點(diǎn)擊,手指點(diǎn)按,或者其它的一些事件,導(dǎo)致應(yīng)用狀態(tài)的改變,你將會(huì)看到下面的方法依次被調(diào)用;
componentWillReceiveProps
當(dāng)props發(fā)生變化時(shí)執(zhí)行,初始化render時(shí)不執(zhí)行,在這個(gè)回調(diào)函數(shù)里面,你可以根據(jù)屬性的變化,通過調(diào)用this.setState()來更新你的組件狀態(tài),舊的屬性還是可以通過this.props來獲取,這里調(diào)用更新狀態(tài)是安全的,并不會(huì)觸發(fā)額外的render調(diào)用。
componentWillReceiveProps: function(nextProps){ if(nextProps.checked !== undefined){ this.setState({ checked: nextProps.checked }) } }
了解更多點(diǎn)擊此處
shouldComponentUpdate
shouldComponentUpdate函數(shù)是重渲染時(shí)render()函數(shù)調(diào)用前被調(diào)用的函數(shù),它接受兩個(gè)參數(shù):nextProps和nextState,分別表示下一個(gè)props和下一個(gè)state的值。并且,當(dāng)函數(shù)返回false時(shí)候,阻止接下來的render()函數(shù)及后面的 componentWillUpdate,componentDidUpdate 方法的調(diào)用,阻止組件重渲染,而返回true時(shí),組件照常重渲染。
了解更多點(diǎn)擊此處--真的講的好
componentWillUpdate
這個(gè)方法和 componentWillMount 類似,在組件接收到了新的 props 或者 state 即將進(jìn)行重新渲染前,componentWillUpdate(object nextProps, object nextState) 會(huì)被調(diào)用,注意不要在此方面里再去更新 props 或者 state。
componentDidUpdate
這個(gè)方法和 componentDidMount 類似,在組件重新被渲染之后,componentDidUpdate(object prevProps, object prevState) 會(huì)被調(diào)用。可以在這里訪問并修改 DOM。
componentWillUnmount
每當(dāng)React使用完一個(gè)組件,這個(gè)組件必須從 DOM 中卸載后被銷毀,此時(shí) componentWillUnmout 會(huì)被執(zhí)行,完成所有的清理和銷毀工作,在 componentDidMount 中添加的任務(wù)都需要再該方法中撤銷,如創(chuàng)建的定時(shí)器或事件監(jiān)聽器。
當(dāng)再次裝載組件時(shí),以下方法會(huì)被依次調(diào)用:
1、getInitialState
2、componentWillMount
3、render
4、componentDidMount
constructor(props) // 初始化參數(shù) componentWillMount() render() // 第一次渲染 componentDidMount() **當(dāng)父組件向子組件傳入props發(fā)生改變后,依次調(diào)用** componentWillReceiveProps(nextProps) shouldComponentUpdate(nextProps, nextState) componentWillUpdate() render() //子組件更新渲染 componentDidUpdate() **當(dāng)組件自身state發(fā)生變化后** componentWillUpdate() render() //組件再次更新渲染 componentDidUpdate() 當(dāng)組件卸載 componentWillUnmount()
與低于React16版本的比較
新增了對(duì)錯(cuò)誤的處理(componentDidCatch)
感謝各位的閱讀!看完上述內(nèi)容,你們對(duì)react生命周期是什么大概了解了嗎?希望文章內(nèi)容對(duì)大家有所幫助。如果想了解更多相關(guān)文章內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。