溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

React總結(jié)篇之二_設(shè)計(jì)高質(zhì)量的React組件

發(fā)布時(shí)間:2020-09-05 04:05:34 來(lái)源:網(wǎng)絡(luò) 閱讀:2147 作者:cylcyl647308 欄目:web開(kāi)發(fā)

一、易于維護(hù)組件的設(shè)計(jì)要素
1.組件劃分的原則:高內(nèi)聚低耦合
(1)高內(nèi)聚:將邏輯緊密相關(guān)的內(nèi)容放在一個(gè)組件內(nèi)。React可以將展示內(nèi)容的JSX、定義行為的JavaScript代碼、甚至定義樣式的css,都可以放在一個(gè)JavaScript文件中,因此React天生具有高內(nèi)聚的特點(diǎn)。
(2)低耦合:不同組件之間的依賴關(guān)系要盡量弱化,也就是每個(gè)組件要盡量獨(dú)立。


二、React組件的數(shù)據(jù)
1.數(shù)據(jù)分類:
React組件的數(shù)據(jù)分為兩種:prop和state。無(wú)論prop或者state改變,都可能引發(fā)React的重新渲染。那在設(shè)計(jì)一個(gè)組件時(shí),什么時(shí)候選擇prop什么時(shí)候選擇state呢?原則很簡(jiǎn)單:prop是組件的對(duì)外接口,state是組件的內(nèi)部狀態(tài),對(duì)外用prop,內(nèi)部用state。

2.Prop:property的縮寫(xiě),是從外部傳遞給組件的數(shù)據(jù),一個(gè)React組件通過(guò)定義自己能夠接受的prop就定義了自己的對(duì)外公共接口。我們先從外部世界看prop是如何使用的:
<SampleButton id="sample" borderWidth={2} onClick={onButtonClick} style={{color:"red"}}/> 上面創(chuàng)建了名為SampleButton的組件實(shí)例,使用了名字分別為id、borderWidth、onClick和style的prop。此處注意:HTML組件屬性的值都是字符串類型,即使是內(nèi)嵌JavaScript,也依然是字符串形式表示代碼。但React組件的prop所能支持的類型除了字符串、可以是任何一種JavaScript語(yǔ)句支持的數(shù)據(jù)類型,如:數(shù)字類型、函數(shù)類型、style的值是一個(gè)包含color字段的對(duì)象,當(dāng)prop的類型不是字符串類型時(shí),在JSX中必須用花括號(hào){}將prop值包住,所以style的值有兩層花括號(hào),外層花括號(hào)代表的是JSX的語(yǔ)法,內(nèi)層花括號(hào)表示這是一個(gè)對(duì)象常量。
Prop要反饋數(shù)據(jù)給外部世界,使用函數(shù)類型的prop,這等于父組件給了子組件一個(gè)回調(diào)函數(shù),子組件在恰當(dāng)?shù)臅r(shí)機(jī)調(diào)用函數(shù)類型的prop,可以帶上必要額參數(shù),這樣就把數(shù)據(jù)傳遞給外部世界。

3.React要求render函數(shù)只能返回一個(gè)元素!

4.組件內(nèi)部接收傳入的prop:
(1)首先是構(gòu)造函數(shù),如下:
class Counter extends Component {
constructor(props){
super(props);
this.onClickIncrementButon = this.onClickIncrementButon.bind(this);
this.onClickDecrementButon = this.onClickDecrementButon.bind(this);
this.state = {
count : props.initValue || 0
}
}
}
注意:組件定義自己的構(gòu)造函數(shù),一定要在構(gòu)造函數(shù)的第一行通過(guò)super調(diào)用父類也就是React.Component的構(gòu)造函數(shù);如果未調(diào)用,那么組件實(shí)例被構(gòu)造之后,類實(shí)例的所有成員函數(shù)就無(wú)法通過(guò)this.props訪問(wèn)到父組件傳過(guò)來(lái)的props值。很明顯,給this.props賦值是React.Component構(gòu)造函數(shù)的工作之一。在Counter的構(gòu)造函數(shù)中還給兩個(gè)成員函數(shù)綁定了當(dāng)前this的執(zhí)行環(huán)境,因?yàn)镋S6方法創(chuàng)建的React類并不自動(dòng)給我們綁定this到當(dāng)前實(shí)例對(duì)象。

我的理解:
Component是React內(nèi)的一個(gè)基類,用于繼承和創(chuàng)建React自定義組件。ES6規(guī)范下的面向?qū)ο髮?shí)現(xiàn)起來(lái)非常精簡(jiǎn),class關(guān)鍵字可以快速創(chuàng)建一個(gè)類,而Component類內(nèi)的所有屬性和方法均可以通過(guò)this訪問(wèn)。換而言之,在Component內(nèi)的任意方法內(nèi),可以通過(guò)this.xxx的方式調(diào)用該Component的其他屬性和方法。
constructor:類的默認(rèn)方法,通過(guò)new命令生成對(duì)象實(shí)例時(shí),自動(dòng)調(diào)用該方法。一個(gè)類必須有constructor方法,如果沒(méi)有顯示定義,一個(gè)空的constructor方法會(huì)被默認(rèn)添加;
super:子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例會(huì)報(bào)錯(cuò)。這是因?yàn)樽宇愖约旱膖his對(duì)象,必須先通過(guò)父類的構(gòu)造函數(shù)完成塑造,得到與父類同樣的屬性和方法,然后再對(duì)其加工,加上子類自己的實(shí)例屬性和方法。如果不調(diào)用super方法,子類就得不到this對(duì)象(子類是沒(méi)有自己的 this 對(duì)象的,它只能繼承自父類的 this 對(duì)象,然后對(duì)其進(jìn)行加工,而super( )就是將父類中的this對(duì)象繼承給子類的。沒(méi)有 super,子類就得不到 this 對(duì)象);
super(props):在constructor中可以使用this.props;
this:在ES6語(yǔ)法下,類的每個(gè)成員函數(shù)在執(zhí)行時(shí)的this并不是和類實(shí)例自動(dòng)綁定的。而在構(gòu)造函數(shù)中,this就是當(dāng)前組件實(shí)例。所以,為了方便將來(lái)的調(diào)用,往往在構(gòu)造函數(shù)中將這個(gè)實(shí)例的特定函數(shù)綁定this為當(dāng)前實(shí)例。this.onClickIncrementButon = this.onClickIncrementButon.bind(this),就是通過(guò)bind方法讓當(dāng)前實(shí)例中onClickIncrementButon函數(shù)被調(diào)用時(shí),this始終指向當(dāng)前組件實(shí)例

(2)讀取prop值:
在構(gòu)造函數(shù)中可以通過(guò)props獲得傳入的prop值,在其他函數(shù)中可通過(guò)this.props訪問(wèn)傳入prop的值。
const {caption} = this.props;
以上,我們使用了ES6的解構(gòu)賦值語(yǔ)法,從this.props中獲得了名為caption的prop值。

5.propTypes檢查:
組件支持哪些prop;
每個(gè)prop應(yīng)該是什么樣的格式;
如:對(duì)于Counter組件的propTypes定義代碼如下:
Counter.propTypes = {
caption : propTypes.string.isRquired,
initVlue : propTypes.number
}
其中要求caption必須是string類型,initVlue必須是number類型,另外,caption帶上了isRquired,表示使用Counter組件必須指定caption,而initVlue如果沒(méi)有也沒(méi)關(guān)系。
propTypes雖然能在開(kāi)發(fā)階段發(fā)現(xiàn)代碼中的問(wèn)題,但是放在產(chǎn)品環(huán)境就不大合適了:首先,占用一些代碼空間,耗CPU計(jì)算資源;其次,在產(chǎn)品環(huán)境下做propTypes檢查沒(méi)有什么幫助,在最終用戶的瀏覽器Console中輸出這些錯(cuò)誤信息沒(méi)什么意義。所以,最好的方式是,開(kāi)發(fā)者在代碼中定義propTypes,但在發(fā)布產(chǎn)品代碼時(shí),用一種自動(dòng)的方式將propTypes去掉。現(xiàn)有的babel-react-optimize具有這個(gè)功能,可以通過(guò)npm安裝,但是應(yīng)該確保只在發(fā)布產(chǎn)品代碼時(shí)使用它。

6.初始化state:
通常在組件類的構(gòu)造函數(shù)結(jié)尾處初始化state,如下:
constructor(props){
......
this.state = {
count:props.initValue || 0
}
}
因?yàn)閕nitValue是一個(gè)可選的props,考慮到父組件沒(méi)有指定這個(gè)props值的情況,我們優(yōu)先使用傳入屬性的initVlue,如果沒(méi)有,就使用默認(rèn)值0。
組件的state必須是一個(gè)JavaScript對(duì)象?。?!
以上,可使用React的defaultProps功能,如下:
Counter.defaultProps = {0}

7.改變組件的state,如下:
onClickIncrementButton () {
this.setState({count : this.state.count + 1})
}
在代碼中,this.state可以讀取到組件當(dāng)前的state。注意:改變組件state必須要使用this.setState函數(shù)而不能直接去修改this.state。直接修改this.state的值,雖然事實(shí)上改變了組件的內(nèi)部狀態(tài),但只是野蠻的修改了state,并沒(méi)有驅(qū)動(dòng)組件進(jìn)行重新渲染,這樣就無(wú)法反應(yīng)this.state值的變化;而this.setState()函數(shù)所做的事情,首先是改變this.state的值,然后驅(qū)動(dòng)組件經(jīng)歷更新過(guò)程,這樣才有機(jī)會(huì)讓this.state里新的值出現(xiàn)在界面上。

8.prop和state的對(duì)比

  • prop用于定義外部接口,state用于記錄內(nèi)部狀態(tài)
  • prop的賦值在外部世界使用組件時(shí),state的賦值在組件內(nèi)部
  • 組件不應(yīng)該改變prop的值,而state存在的目的就是讓組件來(lái)改變的
    組件的state存在就是為了被修改,每一次通過(guò)this.setState函數(shù)修改state就改變了組件的狀態(tài),然后通過(guò)渲染過(guò)程把這種變化體現(xiàn)出來(lái);
    但是,組件是絕不應(yīng)該去修改傳入的props值的,假如父組件包含多個(gè)子組件,然后把一個(gè)JavaScript對(duì)象作為props傳給這幾個(gè)子組件,而某個(gè)組組件竟然改變了這個(gè)對(duì)象的內(nèi)部值,那么,接下來(lái)其他子組件讀取這個(gè)對(duì)象會(huì)得到什么值呢?當(dāng)時(shí)讀取了修改過(guò)的值,但是其他子組件是每次渲染都讀取這個(gè)props的值呢?還是只讀一次就用哪個(gè)最初的值呢?都有可能。也就是說(shuō)一個(gè)子組件去修改props中的值,可能讓程序陷入一團(tuán)混亂,違背了React設(shè)計(jì)的初衷
    UI = render(data)
    React組件扮演的是render函數(shù)的角色,應(yīng)該是一個(gè)沒(méi)有副作用的純函數(shù),修改props的值,是一個(gè)副作用,組件應(yīng)該避免。
    嚴(yán)格來(lái)說(shuō),React并沒(méi)有辦法阻止你去修改傳入的props對(duì)象,所以,每個(gè)開(kāi)發(fā)者就把這當(dāng)做一個(gè)規(guī)定。

三、組件的生命周期
生命周期可能會(huì)經(jīng)歷3個(gè)過(guò)程:

  • 裝載過(guò)程(Mount):組件第一次在DOM數(shù)中渲染的過(guò)程;
  • 更新過(guò)程(Update):組件被重新渲染的過(guò)程;
  • 卸載過(guò)程(Unmount):組件從DOM中刪除的過(guò)程。

1.裝載過(guò)程,依次調(diào)用的函數(shù)如下:

  • constructor
  • getInitialState
  • getDefaultProps
  • componentWillMount
  • render
  • componentDidMount

1.1 constructor
是ES6中每個(gè)類的構(gòu)造函數(shù),要?jiǎng)?chuàng)建一個(gè)組件類的實(shí)例,當(dāng)然會(huì)調(diào)用對(duì)應(yīng)的構(gòu)造函數(shù);
注意:無(wú)狀態(tài)的React組件不需要定義構(gòu)造函數(shù),一個(gè)組件需要構(gòu)造函數(shù),往往為下面的目的:
(1)初始化state,因?yàn)榻M件生命周期中任何函數(shù)都可能會(huì)訪問(wèn)state,那整個(gè)生命周期中第一個(gè)被調(diào)用的構(gòu)造函數(shù)自然是初始化state最理想的地方;
(2)綁定成員函數(shù)的this環(huán)境

1.2 getInitialState和getDefaultProps
待完成........

1.3 render
一個(gè)React組件必須要實(shí)現(xiàn)render函數(shù),因?yàn)樗蠷eact組件的父類React.Component類對(duì)除render類之外的生命周期函數(shù)都有默認(rèn)實(shí)現(xiàn)。
render函數(shù)并不做實(shí)際的渲染動(dòng)作,而是返回一個(gè)JSX描述的結(jié)構(gòu),最終由React來(lái)操作渲染過(guò)程。某些特殊組件的作用不是渲染界面,或者,組件在某些情況下選擇沒(méi)有東西可畫(huà),那就讓render函數(shù)返回一個(gè)null或者false,等于告訴React,這個(gè)組件這次不需要渲染任何DOM元素。
注意:render函數(shù)應(yīng)該是一個(gè)純函數(shù),完全根據(jù)this.props和this.state來(lái)決定返回的結(jié)果,而且不要產(chǎn)生任何副作用。在render中調(diào)用this.setState是錯(cuò)的,因?yàn)橐粋€(gè)純函數(shù)不應(yīng)該引起狀態(tài)的改變。

1.4 componentWillMount和componentDidMount
在裝載過(guò)程中,componentWillMount在調(diào)用render之前被調(diào)用,componentDidMount在調(diào)用render之后被調(diào)用。
通常不用定義componentWillMount函數(shù),所有可以在componentWillMount中做的事情都可以提前到constructor中去做。
而componentDidMount作用很大!render函數(shù)在調(diào)用完之后,componentDidMount并不是會(huì)被立刻調(diào)用,componentDidMount被調(diào)用的時(shí)候,render函數(shù)返回的東西已經(jīng)引發(fā)了渲染,組件已經(jīng)被裝載到了DOM樹(shù)上。由于render函數(shù)只返回一個(gè)JSX表示的對(duì)象,然后React庫(kù)根據(jù)返回對(duì)象來(lái)決定如何渲染。而React庫(kù)肯定要把所有組件返回的結(jié)果綜合起來(lái),才知道如何產(chǎn)生對(duì)應(yīng)的DOM修改,所以,當(dāng)有多個(gè)組件時(shí),只有React庫(kù)調(diào)用多個(gè)組件的render函數(shù)之后,才有可能完成裝載,這時(shí)才會(huì)依次調(diào)用各個(gè)組件的componentDidMount函數(shù)作為裝載過(guò)程的收尾。
兩者的區(qū)別:componentWillMount可以在服務(wù)器端被調(diào)用,也可以在瀏覽器端被調(diào)用,而componentDidMount只能在瀏覽器端被調(diào)用!

2.更新過(guò)程:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
并不是所有的更新過(guò)程都會(huì)執(zhí)行全部函數(shù)

2.1 componentWillReceiveProps(nextProps)
只要是父組件的render函數(shù)被調(diào)用,在render函數(shù)里面被渲染的子組件就會(huì)經(jīng)歷更新過(guò)程,不管父組件傳給子組件的props有沒(méi)有改變,都會(huì)觸發(fā)子組件的componentWillReceiveProps。所以,這個(gè)函數(shù)有必要把傳入?yún)?shù)nextProps和this.props做對(duì)比,nextProps代表的是這一次渲染傳入的props值,this.props代表上一次渲染時(shí)的props值,只有兩者有變化的時(shí)候才調(diào)用this.setState更新內(nèi)部狀態(tài),這是提高React性能的重要方式。
注意:通過(guò)this.setState方法觸發(fā)的更新過(guò)程不會(huì)調(diào)用這個(gè)函數(shù),這是因?yàn)檫@個(gè)函數(shù)適合根據(jù)新的props值(nextProps)來(lái)計(jì)算出是不是要更新內(nèi)部狀態(tài)state。更新組件內(nèi)部狀態(tài)的方法就是this.setState,如果this.setState的調(diào)用導(dǎo)致componentWillReceiveProps再一次被調(diào)用,那就是一個(gè)死循環(huán)了。

2.2 shouldComponentUpdate(nextProps,nextState)
render和shouldComponentUpdate是React生命周期函數(shù)中唯二兩個(gè)要求有返回結(jié)果的函數(shù)。render函數(shù)返回的結(jié)果用于構(gòu)造DOM對(duì)象,而shouldComponentUpdate返回一個(gè)布爾值,告訴React庫(kù)這個(gè)組件在這次更新過(guò)程中是否要繼續(xù)。
在更新過(guò)程中,React庫(kù)首先調(diào)用shouldComponentUpdate函數(shù),若返回true,會(huì)繼續(xù)更新過(guò)程,接著調(diào)用render函數(shù),若是false,停止更新過(guò)程。另外,通過(guò)this.setState函數(shù)引發(fā)更新過(guò)程,并不是立刻更新組件的state值,在執(zhí)行到函數(shù)shouldComponentUpdate的時(shí)候,this.state依然是this.setState函數(shù)執(zhí)行之前的值,因此,在shouldComponentUpdate函數(shù)中,可進(jìn)行比較nextProps、nextState、this.props、this.state是否發(fā)生變化,若變化則繼續(xù)更新,是提高React性能的重要方式。

2.3 componentWillUpdate和componentDidUpdate
如果shouldComponentUpdate返回true,React接下來(lái)會(huì)依次調(diào)用對(duì)應(yīng)組件的componentWillUpdate、render和componentDidUpdate函數(shù)。
和裝載過(guò)程不同的是,當(dāng)在服務(wù)器端使用React渲染時(shí),componentDidUpdate函數(shù)并不是只在瀏覽器端才執(zhí)行的。無(wú)論更新過(guò)程發(fā)生在服務(wù)器端還是瀏覽器端,該函數(shù)都會(huì)被調(diào)用。

3.卸載過(guò)程
componentWillUnmount
當(dāng)React組件要從DOM樹(shù)上刪除掉之前,對(duì)應(yīng)的componentWillUnmount會(huì)被調(diào)用,所以該函數(shù)適合做一些請(qǐng)理性的工作。
componentWillUnmount往往和componentDidMount有關(guān),比如,在componentDidMount用非React的方法創(chuàng)造了一些DOM元素,如果不管可能會(huì)造成內(nèi)存泄漏,那就需要在componentWillUnmount中將這些創(chuàng)建的DOM元素清理掉。


四、組件向外傳遞數(shù)據(jù)
1.React中state和prop的局限
React使用state來(lái)存儲(chǔ)狀態(tài)的一個(gè)缺點(diǎn)就是:數(shù)據(jù)的冗余和重復(fù),另外使用prop在多個(gè)父子組件中傳遞數(shù)據(jù)時(shí)也有同樣的問(wèn)題。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI