摘要:在使用組件的進行組件實例化時,得到的便是其返回值。也就是說,如果其子組件的或發生改變時,只會取決于那個組件的方法的返回值。文章為本人原創,原文見本人個博淺析生命周期一淺析生命周期二
Overview
最近常有學習React相關的技術,寫了幾個React的小Demo,使用 React/Express 技術棧。實在太小,羞于拿出來細說。React 的確是一個值得追隨的技術。但React體系實在龐大,我目前僅略知一二。這里要挑出來說的,是React的生命周期機制。Demo的學習過程中,對它的方便、易用之處實在是深有體會,在一些細節處也值得斟酌,在這里做一下記錄,便于分享。
如果你接觸過React,大概對render和componentWillMount等,會相對的熟悉,因為它們再常用不過。但用歸用,其中的一些理論上的細節,往往容易在使用的過程中被忽略,使我們多敲了不少代碼,心很累的 : )
通俗來講,React 將組件 component 在web中的形成、修改和渲染等劃分為若干個階段,組成組件的生命周期。在一個完整的生命周期內,一個組件會經過若干個階段,在特殊的階段組件會調用一個特別的lifecycle method,即生命周期方法。如下:
constructor(props)
componentWillMount()
render()
componentDidMount()
componentWillReceiveProps(nextProps)
shouldComponentUpdate(nextProps, nextState)
componentWillUpdate(nextProps, nextState)
render( )* //理解上與3. render()略有不同,見下。
componentDidUpdate(prevProps, prevState )
componentWillUnmount( )
constructor值得注意,這些生命周期是React 內置的,在特定條件下就會被調用。而開發者可以做的就是 override(重載)這些方法,以實現想要的功能。
constructor(props),組件形成時調用。
constructor 函數可理解為組件的構造函數,從組件的類(class) 實例化一個組件實例。這個函數在組件形成時被調用,是所有生命周期函數中最先執行的。在constructor函數內,如有必要,進行state的初始化以及綁定方法;否則可以省去constructor函數的聲明。
有以下幾點在開發時值得注意:
constructor 函數內,在執行任何statement之前,必須是super() 函數,如果有參數須將參數帶上。這點跟Java很像。
在constructor 函數內,this.props 返回 undefined
不要在初試化state時引用props 里的值,否則每當props更新時,都需要在componentWillReceiveProps 函數內對state進行更新。(同時這也涉及到組件state選取的原則,如有需要請閱讀Thinking in React)
class App extends Component { constructor(props) { super(props);//------------(1) console.log(this.props);// undefined ------------(2) //initialize the state this.state = { value: "", color: props.initialColor // 不可取 ------------(3) } //bind methods this.handleClick = this.handleClick.bind(this); } }componentWillMount
componentWillMount(),在組件首次渲染(render)之前調用。
mount有安裝之意,我們可以理解為組件首次被加載在web中。因此每次頁面加載/刷新,或者某個組件第一次加載進入web時可以調用componentWillMount( ) 函數。舉個例子,在首次進入文章列表時時,可在 componentWillMount 對所有文章進行查詢。這樣,在render之前,就能拿到所有文章的數據,以便在render中使用。
在componentWillMount ( ) 函數內,若對this.state進行更新,無法觸發重新渲染組件。
class PostList extends Component { //... //在componentWillMount 組件內獲取所有博客列表 componentWillMount(){ axios.get("/posts") .then(res=>{ //... }); } //在 render 函數內將拿到的博客列表 渲染在頁面中 render(){ //... } }Render
render()
render 即 渲染函數,是編寫組件代碼時,唯一一個必須的函數。該函數須有返回值,返回一個組件,即最終渲染出來的組件。在使用組件的class進行組件實例化時,得到的便是其返回值。
返回值有兩種類型:
一個父標簽,這個父標簽內可以包含若干個子標簽,在最外層標簽必須只有一個。
false 或者 null,代表不渲染任何DOM
class App extends Component { //... render(){ return (//...) } }
componentDidMount注意:在render函數中只做與返回組件相關的工作,勿在其中對state進行操作,可以保證每次調用render函數,返回的組件都是相同的。否則將加大項目維護成本。
另外,如果shouldComponentUpdate函數返回false,則不執行render函數。關于shouldComponentUpdate將在下面介紹。
componentDidMount(),一旦組件首次加載完成,便會調用
如果需要對渲染出來的DOM節點做任何操作,可以在此處進行。(提示: this.refs 可獲取真實DOM)。
在該組件內設置state將會導致組件被重新渲染。
class App extends Component { //.. componentDidMount(){ //將會觸發組件重新渲染 this.setState({ value: "100" }): //對節點進行操作 this.refs.div.appendChild(newChild); } }
上面對 React生命周期函數中的constructor / componentWillMount / render / componentDidMount 四個函數進行了介紹。下面將繼續介紹另外5個方法。在此之前,先總結一下,下面列表中列出的3.render()與8.render()的在邏輯上的區別和聯系。先上一個列表。
constructor(props)
componentWillMount( )
render( )
componentDidMount( )
componentWillReceiveProps(nextProps)
shouldComponentUpdate(nextProps, nextState)
componentWillUpdate(nextProps, nextState)
render()*
componentDidUpdate(prevProps, prevState)
componentWillUnmount()
「兩個」render( )方法的區別3.render( ) 與 8.render( )*
實質上,這兩個方法毫無區別。但這里為什么要提及它們之間的區別呢?其實,它們只是同一函數 render( ) 在組件生命周期的兩個不同階段的不同理解而已。
前一個 render( ) 方法指在組件第一次被加載進入頁面時,調用的 render( ) 方法;后一個則指除去第一次,之后調用的 render( ) 方法。
因此,我們更愿意稱第一次的 render( ) 方法為 mount( 安裝 ),稱后一個 render( ) 方法為 re-render ( 重新渲染 ) 。這也是為什么組件首次 render 前后的方法名中帶有mount一詞的緣故了。
這是 React 的伎倆,或者設計哲學吧。怎么認為都行,我認為很有趣?
下面介紹的方法,都是圍繞第二個 render( ) ,即重新渲染 re-render 展開的。
componentWillReceivePropscomponentWillReceiveProps(nextprops),已加載的組件在 props 發生變化時調用。
如果需要通過監聽 props 的改變來修改 state 的值,則可以通過重載該函數實現。
需要注意,在有些情況下,組件的 props 未發生改變也會調用該函數。因此如果在該函數內的邏輯,只是想捕獲當前 props 與 接收的 nextProps 的不同來做出一些操作,則最好先將 props 與 nextProps 進行比較。
1.在mounting階段,即首次 render ,不調用 componentWillReceiveProps 方法。理解了兩個 render( ) 的不同,便知道這里是為什么了。
2.this.setState({…}) 不觸發 componentWillReceiveProps 方法。因為該方法只監聽 this.props 的改變,不關心 this.state 值的變化。
class App extends Component { componentWillReceiveProps(nextProps){ //接收的顏色 與 當前顏色不同時 if (this.props.color !== nextProps.color){ ... } } }shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)
返回 true orfalse
要不要更新(重新渲染)組件?淺顯易懂。這個方法的返回值決定了,當 props 或者 state 值發生變化時,組件是否重新渲染。兩種情況:
返回true,重新渲染。緊接著,繼續執行 componentWillUpdate() → render() → componentDidUpdate()。
false,不重新渲染。不再執行任何生命周期函數函數(亦不執行該組件的 render( ) 函數)。但是,并不妨礙其子組件。也就是說,如果其子組件的 props 或 state 發生改變時,只會取決于那個組件的 shouleComponentUpdate ( ) 方法的返回值。道理雖懂,但遇到是可能會犯迷糊,因為開發中常常會遇見組件嵌套的情況,父子組件之間傳遞同一套 props 或 state,一來二去,誰更新誰不更新,容易迷糊,需要仔細咯。
在絕大部分情況下,當 props 或 state 改變時,都是需要重新渲染組件的。
注意,根據 React 官方 的說法,就算 shouldComponentUpdate( ) 方法返回 false,組件也會重新渲染。需要隨時注意官方文檔的變化。
class PostList extends Component { shouldComponentUpdate(nextProps, nextState){ //return true;默認 return false;// 不更新組件 } }componentWillUpdate
componentWillUpdate(nextProps, nextState),當 shouldComponentUpdate( ) 方法返回 true 后調用。
這個方法提供了一個為重新渲染作準備的機會,意思是要在這里,趁接下來的 render( ) 方法重新渲染之前,完成該完成的操作。這個方法在 mount 階段不會被調用,只在 re-render 階段被調用。
注意,不要在該方法內調用 this.setState({…}),如有需要,請在 componentWillReceiveProps( ) 方法中完成。養成良好的編程規范。
class App extends Component { componentWillUpdate(nextProps, nextState){ var isLate = this.nextProps.isLate; if(isLate){ //... } else { //... } } }componentDidUpdate
componentDidUpdate(prevProps, preState),一旦組件首次更新(重新渲染)完成時調用。
因此像 componentDidMount( ) 一樣,如果需要對渲染出來的DOM節點做任何操作,可以在此處進行。(提示: this.refs 可獲取真實DOM)。
在該組件內設置state將會導致組件被重新渲染。
class App extends Component { //.. componentDidUpdate(){ //將會觸發組件重新渲染 this.setState({ value: "100" }); //對節點進行操作 this.refs.div.appendChild(newChild); } }componentWillUnmount
componentWillUnmount(),在組件即將被卸載(或銷毀)之前調用。
在這個方法中,適合做一些清理善后工作。例如清楚timer,取消網絡請求,或者清除在 componentDidMount 或 componentDidUpdate 中生成的相關 DOM 節點。
總結mount 與 re-render 的是有區別的。
mount階段使用前一部分的四個方法( constructor / componentWillMount / render / componentDidMount),圍繞組件首次加載而調用;
后一部分 re-render 相關的,使用 componentWillReceiveProps / shouldComponentUpdate / componentWillUpdate / render / componentDidUpdate ,圍繞組件重新渲染而調用。
我總結了一張流程圖和一個表格,以表示這些周期函數之間的關系,以及在何種情況下會調用這些函數。
注意:componentWillUnmount 方法未包含其中。
mount | props 變化 | state 變化 |
---|---|---|
constructor | componentWillReceiveProps | shouldComponentUpdate |
componentWillMount | shouldComponentUpdate | (return true) ? / 結束 |
render | (return true) ? / 結束 | componentWillUpdate |
componentDidMount | componentWillUpdate | render |
/ | render | componentDidUpdate |
/ | componentDidUpdate | / |
完。
文章為本人原創,原文見本人個博:
淺析「React」生命周期(一)
淺析「React」生命周期(二)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/81485.html
摘要:前言自從發布之后,更新速度日新月異,而生命周期也隨之改變,雖然原有的一些生命周期函數面臨廢棄,但理解其背后更新的機制也是一種學習在這里根據官方文檔以及社區上其他優秀的文章進行一個對于生命周期的總結,大致上分為以下三個模塊新老生命周期的區別為 前言 自從React發布Fiber之后,更新速度日新月異,而生命周期也隨之改變,雖然原有的一些生命周期函數面臨廢棄,但理解其背后更新的機制也是一種...
摘要:一前言的垃圾回收機制使用垃圾回收機制來自動管理內存。垃圾回收器只會針對新生代內存區老生代指針區以及老生代數據區進行垃圾回收。分別對新生代和老生代使用不同的垃圾回收算法來提升垃圾回收的效率。 V8 實現了準確式 GC,GC 算法采用了分代式垃圾回收機制。因此,V8 將內存(堆)分為新生代和老生代兩部分。 一、前言 V8的垃圾回收機制:JavaScript使用垃圾回收機制來自動管理內存。垃...
摘要:哈哈,我理解,架構就是骨架,如下圖所示譯年月個有趣的和庫前端掘金我們創辦的使命是讓你及時的了解開發中最新最酷的趨勢。 翻譯 | 上手 Webpack ? 這篇就夠了! - 掘金譯者:小 boy (滬江前端開發工程師) 本文原創,轉載請注明作者及出處。 原文地址:https://www.smashingmagazine.... JavaSrip... 讀 Zepto 源碼之代碼結構 - ...
摘要:前端日報點關注,不迷路精選前端團隊工作流遷移記譯新語法私有屬性知乎專欄前端每周清單大前端技術生命周期模型發布面向生產環境的前端性能優化模塊實現入門淺析知乎專欄中文一個線下沙龍中國最大的前端技術社區單頁面博客從前端到后端基于 2017-06-13 前端日報 點關注,不迷路:-P 精選 ESLint v4.0.0 released - ESLint - Pluggable JavaScri...
閱讀 1750·2021-09-26 09:46
閱讀 3028·2021-09-22 15:55
閱讀 2617·2019-08-30 14:17
閱讀 3033·2019-08-26 11:59
閱讀 1817·2019-08-26 11:35
閱讀 3162·2019-08-26 10:45
閱讀 3159·2019-08-23 18:28
閱讀 1136·2019-08-23 18:21