摘要:此篇文章我們將會繼續(xù)探索組件的特性,特別是生命周期。這些方法叫做組件的生命周期方法且會根據(jù)特定并可預(yù)測的順序被調(diào)用?;旧纤械慕M件的生命周期方法都可以被分割成四個階段初始化掛載階段更新階段卸載階段。
原文:https://medium.com/react-ecosystem/react-components-lifecycle-ce09239010df#.j7h6w8ccc
譯者序:React組件生命周期有很多文章介紹了,這篇作者列出了很多開發(fā)中可能不會注意的細(xì)節(jié),比如哪些階段執(zhí)行setState是否會導(dǎo)致render等,對React組件性能優(yōu)化有一定的幫助,故譯之,不當(dāng)之處敬請指正!
github issue: https://github.com/chemdemo/c...
一段探索React自建內(nèi)部構(gòu)造的旅程在先前的文章里我們涵蓋了React基本原理和如何構(gòu)建更加復(fù)雜的交互組件。此篇文章我們將會繼續(xù)探索React組件的特性,特別是生命周期。
稍微思考一下React組件所做的事,首先想到的是一點是:React描述了如何去渲染(DOM)。我們已經(jīng)知道React使用render()方法來達(dá)到這個目的。然而僅有render()方法可能不一定都能滿足我們的需求。如果在組件rendered之前或之后我們需要做些額外的事情該怎么做呢?我們需要做些什么以避免重復(fù)渲染(re-render)呢?
看起來我們需要對組件(運行)的各個階段進(jìn)行控制,組件運行所有涉及的各個階段叫做組件的生命周期,并且每一個React組件都會經(jīng)歷這些階段。React提供了一些方法并在組件處于相應(yīng)的階段時通知我們。這些方法叫做React組件的生命周期方法且會根據(jù)特定并可預(yù)測的順序被調(diào)用。
基本上所有的React組件的生命周期方法都可以被分割成四個階段:初始化、掛載階段(mounting)、更新階段、卸載階段(unmounting)。讓我們來近距離分別研究下各個階段。
初始化階段初始化階段就是我們分別通過getDefaultProps()和getInitialState()方法定義this.props默認(rèn)值和this.state初始值的階段。
getDefaultProps()方法被調(diào)用一次并緩存起來——在多個類實例之間共享。在組件的任何實例被創(chuàng)建之前,我們(的代碼邏輯)不能依賴這里的this.props。這個方法返回一個對象并且屬性如果沒有通過父組件傳入的話相應(yīng)的屬性會掛載到this.props對象上。
getInitialState()方法也只會被調(diào)用一次,(調(diào)用時機)剛好是mounting階段開始之前。返回值將會被當(dāng)成this.state的初始值,且必須是一個對象。
現(xiàn)在我們來證明上面的猜想,實現(xiàn)一個顯示的值可以被增加和減少的組件,基本上就是一個擁有“+”和“-”按鈕的計數(shù)器。
var Counter = React.createClass({ getDefaultProps: function() { console.log("getDefaultProps"); return { title: "Basic counter!!!" } }, getInitialState: function() { console.log("getInitialState"); return { count: 0 } }, render: function() { console.log("render"); return (); }, handleIncrement: function() { var newCount = this.state.count + 1; this.setState({count: newCount}); }, handleDecrement: function() { var newCount = this.state.count - 1; this.setState({count: newCount}); }, propTypes: { title: React.PropTypes.string } }); ReactDOM.render( React.createElement(Counter), document.getElementById("app-container") );{this.props.title}
{this.state.count}
我們通過getDefaultProps()方法配置一個“title”屬性,如果沒有傳入則提供一個默認(rèn)值。然后通過getInitialState()為組件設(shè)置一個初始state值“{count: 0}”。如果運行這段代碼你將會看到控制臺輸出如下結(jié)果:
現(xiàn)在我們想要讓Counter組件可以設(shè)置this.state.count初始值和增加/減少的步長值,但依然提供一個默認(rèn)值:
var Component = React.createClass({ getDefaultProps: function() { console.log("getDefaultProps"); return { title: "Basic counter!!!", step: 1 } }, getInitialState: function() { console.log("getInitialState"); return { count: (this.props.initialCount || 0) }; }, render: function() { console.log("render"); var step = this.props.step; return (); }, updateCounter: function(value) { var newCount = this.state.count + value; this.setState({count: newCount}); }, propTypes: { title: React.PropTypes.string, initialCount: React.PropTypes.number, step: React.PropTypes.number } }); ReactDOM.render( React.createElement(Component, {initialCount: 5, step: 2}), document.getElementById("app-container") );{this.props.title}
{this.state.count}
這里通過Function.prototype.bind使用偏函數(shù)應(yīng)用(Partial Application)來達(dá)到復(fù)用代碼的目的。
現(xiàn)在我們擁有了一個可定制化的組件。
增長(Mounting)階段Mounting階段發(fā)生在組件即將被插入到DOM之前。這個階段有兩個方法可以用:componentWillMount()和componentDidMount()。
componentWillMount()方法是這個階段最先調(diào)用的,它只在剛好初始渲染(initial rendering)發(fā)生之前被調(diào)用一次,也就是React在DOM插入組件之前。需要注意的是在此處調(diào)用this.setState()方法將不會觸發(fā)重復(fù)渲染(re-render)。如果添加下面的代碼到計數(shù)器組件我們將會看到此方法在getInitialState()之后且render()之前被調(diào)用。
getInitialState: function() {...}, componentWillMount: function() { console.log("componentWillMount"); },
componentDidMount()是這個階段第二個被調(diào)用的方法,剛好發(fā)生在React插入組件到DOM之后,且也只被調(diào)用一次?,F(xiàn)在可以更新DOM元素了,這意味著這個方法是初始化其他需要訪問DOM或操作數(shù)據(jù)的第三方庫的最佳時機。
假設(shè)我們想要通過API拉取數(shù)據(jù)來初始化組件。我們應(yīng)該直接在計數(shù)器組件的componentDidMount()方法拉取數(shù)據(jù),但是這讓組件看起來有太多邏輯了,更可取的方案是使用容器組件來做:
var Container = React.createClass({ getInitialState: function() { return { data: null, fetching: false, error: null }; }, render: function() { if (this.props.fetching) { returnLoading...; } if (this.props.error) { return ({this.state.error.message}); } return}, componentDidMount: function() { this.setState({fetching: true}); Axios.get(this.props.url).then(function(res) { this.setState({data: res.data, fetching: false}); }).catch(function(res) { this.setState({error: res.data, fetching: false}); }); } });
更新階段Axios是一個基于priomise的跨瀏覽器和Node.js的HTTP客戶端。
當(dāng)組件的屬性或者狀態(tài)更新時也需要一些方法來供我們執(zhí)行代碼,這些方法也是組件更新階段的一部分且按照以下的順序被調(diào)用:
1、當(dāng)從父組件接收到新的屬性時:
2、當(dāng)通過this.setState()改變狀態(tài)時:
此階段React組件已經(jīng)被插入DOM了,因此這些方法將不會在首次render時被調(diào)用。
最先被調(diào)用的方法是componentWillReceiveProps(),當(dāng)組件接收到新屬性時被調(diào)用。我們可以利用此方法為React組件提供一個在render之前修改state的機會。在此方法內(nèi)調(diào)用this.setState()將不會導(dǎo)致重復(fù)render,然后可以通過this.props訪問舊的屬性。例如計數(shù)器組件,如果我們想要在任何時候父組件傳入“initialCount”時更新狀態(tài),可以這樣做:
... componentWillReceiveProps: function(newProps) { this.setState({count: newProps.initialCount}); }, ...
shouldComponentUpdate()方法允許我們自行決定下一個state更新時是否觸發(fā)重復(fù)render。此方法返回一個布爾值,且默認(rèn)是true。但是我們也可以返回false,這樣下面的(生命周期)方法將不會被調(diào)用:
componentWillUpdate()
render()
componentDidUpdate()
當(dāng)有性能瓶頸時也可以使用shouldComponentUpdate()方法(來優(yōu)化)。尤其是數(shù)百個組件一起時重新render的代價將會十分昂貴。為了證明這個猜想我們來看一個例子:
var TextComponent = React.createClass({ shouldComponentUpdate: function(nextProps, nextState) { if (this.props.text === nextProps.text) return false; return true; }, render: function() { return ; } });
此例中無論何時父組件傳入一個“text”屬性到TextComponent并且text屬性等于當(dāng)前的“text”屬性時,組件將會不會重復(fù)render。
當(dāng)接收到新的屬性或者state時在render之前會立刻調(diào)用componentWillUpdate()方法。可以利用此時機來為更新做一些準(zhǔn)備工作,雖然這個階段不能調(diào)用this.setState()方法:
... componentWillUpdate: function(nextProps, nextState) { console.log("componentWillUpdate", nextProps, nextState); }, ...
componentDidUpdate()方法在React更新DOM之后立刻被調(diào)用??梢栽诖朔椒ɡ锊僮鞅桓逻^的DOM或者執(zhí)行一些后置動作(action)。此方法有兩個參數(shù):
prevProps:舊的屬性
prevState:舊的state
這個方法的一個常見使用場景是當(dāng)我們使用需要操作更新后的DOM才能工作的第三方庫——如jQuery插件的時候。在componentDidMount()方法內(nèi)初始化第三方庫,但是在屬性或state更新觸發(fā)DOM更新之后也需要同步更新第三方庫來保持接口一致,這些必須在componentDidUpdate()方法內(nèi)來完成。為了驗證這一點,讓我們看看如何開發(fā)一個Select2庫包裹(wrapper)React組件:
var Select2 = React.createClass({ componentDidMount: function() { $(this._ref).select2({data: this.props.items}); }, render: function() { return ( ); }, componentDidUpdate: function() { $(this._ref).select2("destroy"); $(this._ref).select2({data: this.props.items}); } });卸載階段(unmounting)
此階段React只提供了一個方法:
componentWillUnmount()
它將在組件從DOM卸載之前被調(diào)用。可以在內(nèi)部執(zhí)行任何可能需要的清理工作,如無效的計數(shù)器或者清理一些在componentDidMount()/componentDidUpdate()內(nèi)創(chuàng)建的DOM。比如在Select2組件里邊我們可以這樣子:
... componetWillUnmount: function(){ $(this._ref).select2("destroy"); }, ...概述
React為我們提供了一種在創(chuàng)建組件時申明一些將會在組件生命周期的特定時機被自動調(diào)用的方法的可能?,F(xiàn)在我們很清晰的理解了每一個組件生命周期方法所扮演的角色以及他們被調(diào)用的順序。這使我們有機會在組件創(chuàng)建和銷毀時執(zhí)行一些操作。也允許我們在當(dāng)屬性和狀態(tài)變化時做出相應(yīng)的反應(yīng)從而更容易的整合第三方庫和追蹤性能問題。
希望您覺得此文對您有用,如果是這樣,請推薦之!??!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/80288.html
摘要:譯的生命周期的使用場景原文鏈接作者翻譯上名這個圖片,就是組件的生命周期,從形成到銷毀的過程。這并不意味著沒有用。最常見的用例更新以響應(yīng)或更改。是否可以調(diào)用總結(jié)在理想的世界中,我們不會使用生命周期方法。 [譯]React 的生命周期的使用場景 showImg(https://segmentfault.com/img/bVLTCt?w=2000&h=800); 原文鏈接:React Lif...
摘要:譯者前端小智原文就像人們對更新移動應(yīng)用程序和操作系統(tǒng)感到興奮一樣,開發(fā)人員也應(yīng)該對更新框架感到興奮。錯誤邊界是一種組件。注意將作為值傳遞進(jìn)去并不會導(dǎo)致使用。如果兩者不同,則返回一個用于更新狀態(tài)的對象,否則就返回,表示不需要更新狀態(tài)。 譯者:前端小智 原文:medium.freecodecamp.org/why-react16… 就像人們對更新移動應(yīng)用程序和操作系統(tǒng)感到興奮一樣,開發(fā)人員也應(yīng)...
摘要:可以說,相比繼承而已,更喜歡這種組合的方式。需要指出的是,是可以包含在其他的中的程序會在控制臺打印出。包含多個我們的要包裹在數(shù)組當(dāng)中,提醒了我們可以在組件中包含多個注意事項這里有幾件事需要引起我們的注意,當(dāng)我們使用的時候。 update: Mixin 只適用于 ES5。如果你的項目里面用的是 ES6 ,可以采用高階組件來實現(xiàn) Mixin 的功能。 我使用 React.js 構(gòu)建大型項目...
摘要:翻譯瘋狂的技術(shù)宅作者英文標(biāo)題英文地址說明本文首發(fā)于公眾號在本文中,我將向你展示如何使用和庫中的生命周期方法來實現(xiàn)頁面的過渡效果。我們還用創(chuàng)建了一個變量,可以用它來對封裝的子組件中的的不同樣式屬性實現(xiàn)動畫效果。用渲染,并且或者插入動畫狀態(tài)值。 翻譯:瘋狂的技術(shù)宅作者:Martin Haagensli英文標(biāo)題:Animated page transitions with React Rou...
摘要:原文作者譯者博軒于年月的中引入,作為在函數(shù)組件中使用狀態(tài)和生命周期的一種方法。雖然函數(shù)組件之前被稱為無狀態(tài)組件,但是的出現(xiàn),使得這些函數(shù)組件可以使用狀態(tài)。因此,現(xiàn)在許多人將它們視為功能組件。 原文:What are React Hooks?作者:Robin Wieruch譯者:博軒 showImg(https://segmentfault.com/img/remote/14600000...
閱讀 1134·2021-11-25 09:43
閱讀 1725·2019-08-30 13:59
閱讀 1752·2019-08-30 11:22
閱讀 2199·2019-08-30 11:06
閱讀 1367·2019-08-28 17:51
閱讀 3848·2019-08-26 12:12
閱讀 841·2019-08-26 12:11
閱讀 498·2019-08-26 12:10