摘要:例如一個(gè)嬰兒在出生前和出生后,這是兩個(gè)不同的階段。主要是在更新前,最后一次修改,而不會(huì)觸發(fā)重新渲染。組件更新的整個(gè)過(guò)程控制臺(tái)打印第一個(gè)是初始化調(diào)用的,不是更新的過(guò)程。
概述
我們先來(lái)理一理React的生命周期方法有哪些:
componentWillMount渲染前調(diào)用一次,這個(gè)時(shí)候DOM結(jié)構(gòu)還沒(méi)有渲染。
componentDidMount渲染完成后調(diào)用一次,這個(gè)時(shí)候DOM結(jié)構(gòu)已經(jīng)渲染了。這個(gè)時(shí)候就可以初始化其他框架的設(shè)置了,如果利用jQuery綁定事件等等。
componentWillReceiveProps初始化渲染不會(huì)調(diào)用,在接收到新的props時(shí),會(huì)調(diào)用這個(gè)方法。
shouldComponentUpdate初始化渲染不會(huì)調(diào)用,接收到新的props或state時(shí)調(diào)用。
componentWillUpdate初始化渲染不會(huì)調(diào)用,更新前調(diào)用。
componentDidUpdate初始化渲染不會(huì)調(diào)用,更新后調(diào)用。
componentWillUnmount組件移除前調(diào)用。
根據(jù)執(zhí)行的時(shí)機(jī),這些方法可以分為三類(lèi)。
組件渲染前后會(huì)執(zhí)行,而且只會(huì)執(zhí)行一次,看個(gè)例子
var A = React.createClass({ componentWillMount: function () { console.log("A componentWillMount"); }, componentDidMount: function () { console.log("A componentDidMount"); }, render: function () { console.log("A render"); return null; } }); React.render(, document.getElementById("example")); #控制臺(tái)打印 A componentWillMount A render A componentDidMountcomponentWillMount
componentWillMount里允許我們初始化前最后一次對(duì)state進(jìn)行修改,而不會(huì)觸發(fā)重新渲染。
var A = React.createClass({ getInitialState: function () { return {init: false}; }, componentWillMount: function () { this.setState({init: true}); console.log("A componentWillMount"); }, componentDidMount: function () { console.log("A componentDidMount"); }, render: function () { console.log("A render:" + this.state.init); return null; } }); React.render(, document.getElementById("example")); #控制臺(tái)打印 A componentWillMount A render:true A componentDidMount
如果在componentDidMount中setState,結(jié)果就會(huì)是這樣的。
var A = React.createClass({ getInitialState: function () { return {init: false}; }, componentWillMount: function () { console.log("A componentWillMount"); }, componentDidMount: function () { this.setState({init: true}); console.log("A componentDidMount"); }, render: function () { console.log("A render:" + this.state.init); return null; } }); React.render(, document.getElementById("example")); #控制臺(tái)打印 A componentWillMount A render:false A componentDidMount A render:true
也許會(huì)有人會(huì)問(wèn)了:在這個(gè)方法中
componentDidMount: function () { this.setState({init: true}); console.log("A componentDidMount"); }
先調(diào)用了setState,為啥不是先打印 ‘A render:true’后打印‘A componentDidMount’呢?
setState并不是一個(gè)同步的方法,可以理解為異步。
這里容易犯的錯(cuò)誤就是,setState完后,馬上就獲取state的值做處理,結(jié)果獲取的還是老的state。
var A = React.createClass({ getInitialState: function () { return {init: false}; }, componentWillMount: function () { console.log("A componentWillMount"); }, componentDidMount: function () { this.setState({init: true}); console.log("A componentDidMount:" + this.state.init); }, render: function () { console.log("A render:" + this.state.init); return null; } }); React.render(, document.getElementById("example")); #控制臺(tái)打印 A componentWillMount A render:false A componentDidMount:false A render:true
如果想setState后獲取到更新的值,可以放在回調(diào)里
var A = React.createClass({ getInitialState: function () { return {init: false}; }, componentWillMount: function () { console.log("A componentWillMount"); }, componentDidMount: function () { this.setState({init: true}, function () { console.log("callback:" + this.state.init); }); console.log("A componentDidMount"); }, render: function () { console.log("A render:" + this.state.init); return null; } }); React.render(, document.getElementById("example")); #控制臺(tái)打印 A componentWillMount A render:false A componentDidMount A render:true callback:truecomponentDidMount
componentDidMount渲染完成后執(zhí)行一次,一般我們會(huì)在這里異步獲取數(shù)據(jù),重新渲染頁(yè)面。例如
var A = React.createClass({ getInitialState: function () { return {data: []}; }, fetchData: function (callback) { setTimeout( function () { callback([1, 2, 3]); }, 1000 ); }, componentDidMount: function () { this.fetchData(function (data) { this.setState({data: data}); }.bind(this)); }, render: function () { var data = this.state.data; return ( data.length ?
官方文檔上也說(shuō)的很清楚,建議我們?cè)赾omponentDidMount中添加ajax,因?yàn)檫@是DOM已經(jīng)完成了初始化的渲染,在componentWillMount中獲取也可以,例如上面的例子,換在componentWillMount中獲取數(shù)據(jù),完全OK的。但是不建議大家這么干,第一個(gè)是官方不推薦,另一個(gè)因?yàn)镈OM還沒(méi)有渲染,這個(gè)時(shí)候的一些DOM操作就會(huì)出錯(cuò)!
嵌套看個(gè)父子組件的執(zhí)行過(guò)程,加深對(duì)初始化渲染過(guò)程的理解。
var Child = React.createClass({ componentWillMount: function () { console.log("Child componentWillMount"); }, componentDidMount: function () { console.log("Child componentDidMount"); }, render: function () { console.log("Child render"); return null; } }); var Parent = React.createClass({ componentWillMount: function () { console.log("Parent componentWillMount"); }, componentDidMount: function () { console.log("Parent componentDidMount"); }, render: function () { console.log("Parent render"); return組件更新; } }); React.render( , document.getElementById("example")); #控制臺(tái)打印 Parent componentWillMount Parent render Child componentWillMount Child render Child componentDidMount Parent componentDidMount
更新方法只會(huì)在組件初始化渲染完成后且觸發(fā)了重新渲染的條件才會(huì)執(zhí)行。更新方法同掛載方法分處組件生命周期的不同的階段。例如一個(gè)嬰兒在出生前和出生后,這是兩個(gè)不同的階段。
componentWillReceiveProps組件接收到新的props時(shí)會(huì)調(diào)用,一般在組件嵌套中比較常見(jiàn),單一組件state變化是不會(huì)執(zhí)行這個(gè)函數(shù)的。例如
var A= React.createClass({ componentWillReceiveProps: function (nextProps) { console.log("A componentWillReceiveProps"); }, componentDidMount: function () { this.setState({name: "zzz"}); }, render: function () { return null; } }); React.render(, document.getElementById("example")); 控制臺(tái)啥也沒(méi)打印
因?yàn)閷?duì)組件來(lái)說(shuō),他的props是不可變的。在看另外一個(gè)例子:
var Child = React.createClass({ componentWillReceiveProps: function (nextProps) { console.log("Child componentWillReceiveProps"); }, render: function () { return{this.props.name}; } }); var Parent = React.createClass({ getInitialState: function () { return {name: "xxx"}; }, componentDidMount: function () { this.setState({name: "zzz"}); }, render: function () { return; } }); React.render( , document.getElementById("example")); #控制臺(tái)打印 Child componentWillReceiveProps
盡管沒(méi)有傳遞屬性,但是方法依舊會(huì)執(zhí)行,只不過(guò)nextProps是個(gè)空對(duì)象而已。有人會(huì)問(wèn)了,在Child組件當(dāng)中,初始化渲染的時(shí)候name值為‘xxx’,第二次更新的時(shí)候name值為‘zzz’,為什么會(huì)說(shuō)組件的props是不變的呢?這里不是發(fā)生變化了么?
按照我的個(gè)人理解,組件props不變指的是在它的生命周期的階段中,保持不變。例如初始化渲染的過(guò)程中,如果在componentWillMount方法中,手動(dòng)修改props,控制臺(tái)就會(huì)提示如下警告。組件更新方法主要是相應(yīng)state的變化,此處更不應(yīng)該去修改props。
Warning: Don"t set .props.name of the React component. Instead, specify the correct value when initially creating the element. The element was created by Parent.
componentWillReceiveProps主要是在更新前,最后一次修改state,而不會(huì)觸發(fā)重新渲染。有點(diǎn)類(lèi)似componentWillMount,但是執(zhí)行的時(shí)間不一樣,例如
var Child = React.createClass({ getInitialState: function () { return {show: false}; }, componentWillReceiveProps: function (nextProps) { if (this.props.name !== nextProps.name) { this.setState({show: true}); } }, render: function () { return this.state.show ?{this.props.name}: null; } }); var Parent = React.createClass({ getInitialState: function () { return {name: "xxx"}; }, componentDidMount: function () { this.setState({name: "xxx"}); }, render: function () { return; } }); React.render( , document.getElementById("example"));
我們要盡量避免父子組件當(dāng)中都有state,這樣組件的復(fù)用性就會(huì)降低,一般來(lái)說(shuō)保持最外層的容器組件同服務(wù)器、用戶交互,改變state,而子組件只負(fù)責(zé)通過(guò)props接收數(shù)據(jù),然后渲染頁(yè)面。這也是官方推薦的做法。
shouldComponentUpdate更新前調(diào)用,返回值決定了組件是否更新。例如
var A = React.createClass({ componentDidMount: function () { this.setState({}); }, shouldComponentUpdate: function (nextProps, nextState) { console.log("A shouldComponentUpdate"); return true; }, componentWillUpdate: function () { console.log("A componentWillUpdate"); }, componentDidUpdate: function () { console.log("A componentDidUpdate"); }, render: function () { console.log("A render"); return null ; } }); React.render(, document.getElementById("example")); #控制臺(tái)打印 A render A shouldComponentUpdate A componentWillUpdate A render A componentDidUpdate
第一個(gè)render是初始化。組件會(huì)將render方法的返回值同已有的DOM結(jié)構(gòu)比較,只更新有變動(dòng)的的部分,這個(gè)過(guò)程是需要花費(fèi)時(shí)間的,在這個(gè)方法中我可以決定是否需要更新組件,從而減少性能的損耗。
componentWillUpdate、componentDidUpdatethis.forceUpdate()不會(huì)執(zhí)行shouldComponentUpdate方法,因?yàn)槭菑?qiáng)制更新,不會(huì)因?yàn)閟houldComponentUpdate的返回值決定是否更新,所以跳過(guò)該方法。另外還需要注意的是,this.forceUpdate()調(diào)用會(huì)導(dǎo)致該組件的shouldComponentUpdate不執(zhí)行,對(duì)子組件的shouldComponentUpdate方法沒(méi)有影響。
組件更新前后執(zhí)行,沒(méi)辦法決定組件是否更新,只能進(jìn)行些非狀態(tài)的操作,個(gè)人感覺(jué)用途不太明顯。
組件更新的整個(gè)過(guò)程
var Child = React.createClass({ componentWillReceiveProps: function () { console.log("Child componentWillReceiveProps"); }, shouldComponentUpdate: function (nextProps, nextState) { console.log("Child shouldComponentUpdate"); return true; }, componentWillUpdate: function () { console.log("Child componentWillUpdate"); }, componentDidUpdate: function () { console.log("Child componentDidUpdate"); }, render: function () { console.log("Child render"); return null ; } }); var Parent = React.createClass({ componentDidMount: function () { this.setState({}); }, render: function () { return; } }); React.render( , document.getElementById("example")); #控制臺(tái)打印 Child render Child componentWillReceiveProps Child shouldComponentUpdate Child componentWillUpdate Child render Child componentDidUpdate
第一個(gè)render是初始化調(diào)用的,不是更新的過(guò)程。
移除 componentWillUnmount組件被移除前調(diào)用,這里可以做一些清除工作,例如清除內(nèi)存,解除事件的監(jiān)聽(tīng)等等。
var A = React.createClass({ componentDidMount: function () { this.interval = setInterval( function () { console.log("running"); }, 100 ); }, handleClick: function () { React.unmountComponentAtNode(document.getElementById("example")); }, componentWillUnmount: function () { clearInterval(this.interval); }, render: function () { return ; } }); React.render(, document.getElementById("example"));
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85954.html
摘要:學(xué)習(xí)免不了對(duì)組件生命周期的學(xué)習(xí),我們應(yīng)該掌握最新生命周期,學(xué)以致用,以達(dá)到性能優(yōu)化的目的。 學(xué)習(xí)React免不了對(duì)組件生命周期的學(xué)習(xí),我們應(yīng)該掌握最新生命周期,學(xué)以致用,以達(dá)到性能優(yōu)化的目的。 The Component Lifecycle React Version: 16.3 1 生命周期可視化 高清大圖--歡迎轉(zhuǎn)載 showImg(https://segmentfault.co...
摘要:結(jié)果如下打開(kāi)試試下一步,我們將把組件功能自己設(shè)置定時(shí)器并且能每秒更新。這是一個(gè)設(shè)置定時(shí)器的好地方注意我們是怎么保存定時(shí)器的。我們將在這個(gè)生命周期的函數(shù)方法中卸載掉定時(shí)器最后,我們會(huì)每一秒跑方法。 下面是react官方文檔的個(gè)人翻譯,如有翻譯錯(cuò)誤,請(qǐng)多多指出原文地址:https://facebook.github.io/re... Consider the ticking clock e...
摘要:搭建項(xiàng)目,引入既然學(xué)習(xí),那就從開(kāi)始。項(xiàng)目工程目錄如下編寫(xiě)在我理解看來(lái),項(xiàng)目文件入口即是文件,那么從中編寫(xiě)。官方文檔所述圖片注文章末尾段組件生命周期引入自 Hello Word 1.搭建項(xiàng)目,引入react 既然學(xué)習(xí)react,那就從hello word開(kāi)始。當(dāng)然必不可少的需要引入react,這里我使用的是官網(wǎng)的 Creating a New Application 方式,通過(guò)以下命令...
摘要:理論上,通過(guò)一層層傳遞下去當(dāng)然是沒(méi)問(wèn)題的。不過(guò)這也太麻煩啦,要是能在最外層和最里層之間開(kāi)一個(gè)穿越空間的蟲(chóng)洞就好了。使用看起來(lái)很高大上的使用起來(lái)卻異常簡(jiǎn)單。就像中的全局變量,只有真正全局的東西才適合放在中。 當(dāng)我們寫(xiě)React時(shí),我們總是通過(guò)改變State和傳遞Prop對(duì)view進(jìn)行控制,有時(shí),也會(huì)遇到一點(diǎn)小麻煩。 背景 但是隨著我們的應(yīng)用變的越來(lái)越復(fù)雜,組件嵌套也變的越來(lái)越深,有時(shí)甚至...
摘要:的響應(yīng)核心的響應(yīng)式系統(tǒng)是支撐整個(gè)框架運(yùn)行的關(guān)鍵,也是的核心之一,官方對(duì)這個(gè)核心的分層設(shè)計(jì)得很好也是依靠其驅(qū)動(dòng)原生視圖。我們?nèi)粘S玫降亩加珊诵奶峁瑢?duì)這個(gè)核心稍作修改,去掉和,意外的獲得了一個(gè)極小的響應(yīng)核心,可以運(yùn)行于任何標(biāo)準(zhǔn)引擎下。 showImg(https://segmentfault.com/img/bVPMZy?w=1468&h=826); GitHub: react-vue ...
閱讀 3311·2021-09-09 11:39
閱讀 1240·2021-09-09 09:33
閱讀 1139·2019-08-30 15:43
閱讀 557·2019-08-29 14:08
閱讀 1742·2019-08-26 13:49
閱讀 2390·2019-08-26 10:09
閱讀 1556·2019-08-23 17:13
閱讀 2294·2019-08-23 12:57