亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

characters

React提供了一個聲明式API,因此您無需擔心每次更新的確切更改。這使得編寫應(yīng)用程序變得更加簡單,但在React中如何實現(xiàn)它可能并不明顯。本文解釋了我們在React的“差異化”算法中所做的選擇,以便組件更新可預測,同時對于高性能應(yīng)用程序足夠快。

動機

當您使用React時,您可以在單個時間點將該render()功能視為創(chuàng)建React元素樹。在下一個狀態(tài)或道具更新時,該render()函數(shù)將返回不同的React元素樹。然后React需要弄清楚如何有效地更新UI以匹配最近的樹。

對于產(chǎn)生將一棵樹轉(zhuǎn)換為另一棵樹的最小操作次數(shù)的算法問題,存在一些通用解決方案。然而,現(xiàn)有技術(shù)的算法在O(n3)的順序中具有復雜性,其中n是樹中元素的數(shù)量。

如果我們在React中使用它,則顯示1000個元素需要10億次比較。這太貴了。相反,React基于兩個假設(shè)實現(xiàn)了啟發(fā)式O(n)算法:

  1. 兩種不同類型的元素會產(chǎn)生不同的樹木。

2. 開發(fā)人員可以通過key道具暗示哪些子元素可以在不同的渲染器中保持穩(wěn)定。

實際上,這些假設(shè)對于幾乎所有的實際使用情況都是有效的。

Diffing算法

在分析兩棵樹時,React首先比較兩個根元素。行為根據(jù)根元素的類型而不同。

不同類型的元素

每當根元素具有不同類型時,React就會拆除舊樹并從頭開始構(gòu)建新樹。從去<a><img>,或者<Article><Comment>,或<Button><div>-任何這些將導致完全重建。

拆除樹時,舊的DOM節(jié)點被破壞。組件實例接收componentWillUnmount()。在構(gòu)建新樹時,將新的DOM節(jié)點插入到DOM中。組件實例接收componentWillMount()然后componentDidMount()。任何與舊樹相關(guān)的狀態(tài)都會丟失。

根以下的任何組件也將被卸載并且其狀態(tài)被破壞。例如,差異時:

<div>  <Counter /></div><span>  <Counter /></span>

這將摧毀舊的Counter并重新裝上一個新的。

同一類型的DOM元素

比較相同類型的兩個React DOM元素時,React查看兩者的屬性,保持相同的底層DOM節(jié)點,并僅更新已更改的屬性。例如:

<div className="before" title="stuff" /><div className="after" title="stuff" />

通過比較這兩個元素,React知道只修改className底層DOM節(jié)點。

更新時style,React也知道只更新已更改的屬性。例如:

<div style={{color: 'red', fontWeight: 'bold'}} /><div style={{color: 'green', fontWeight: 'bold'}} />

在這兩個元素之間轉(zhuǎn)換時,React知道只修改color樣式,而不是fontWeight。

在處理DOM節(jié)點之后,React會在子節(jié)點上遞歸。

同一類型的組件元素

當組件更新時,實例保持不變,以便在整個渲染過程中維護狀態(tài)。反應(yīng)更新底層組件實例的道具新元素匹配,并呼吁componentWillReceiveProps()componentWillUpdate()對底層的實例。

接下來,該render()方法被調(diào)用,并且diff算法對先前結(jié)果和新結(jié)果進行遞歸。

遞歸于兒童

默認情況下,React在DOM節(jié)點的子節(jié)點上遞歸時,只是同時迭代兩個子節(jié)點列表,并在出現(xiàn)差異時生成突變。

例如,在兒童的末尾添加元素時,在這兩棵樹之間轉(zhuǎn)換效果很好:

<ul>  <li>first</li>  <li>second</li></ul><ul>  <li>first</li>  <li>second</li>  <li>third</li></ul>

React將匹配兩<li>first</li>棵樹,匹配兩<li>second</li>棵樹,然后插入<li>third</li>樹。

如果你天真地實現(xiàn)它,在開始插入一個元素會導致性能下降。例如,在這兩棵樹之間轉(zhuǎn)換效果不佳:

<ul>  <li>Duke</li>  <li>Villanova</li></ul><ul>  <li>Connecticut</li>  <li>Duke</li>  <li>Villanova</li></ul>

反應(yīng)會產(chǎn)生變異每一個孩子,而不是意識到它可以保留的<li>Duke</li><li>Villanova</li>子樹完好無損。這種低效率可能是一個問題。

Keys

為了解決這個問題,React支持一個key屬性。當孩子擁有密鑰時,React使用該密鑰將原始樹中的孩子與后續(xù)樹中的孩子進行匹配。例如,在key上面的低效率示例中添加a 可以使樹轉(zhuǎn)換高效:

<ul>  
    <li key="2015">Duke</li>  
    <li key="2016">Villanova</li>
</ul>
<ul>  
    <li key="2014">Connecticut</li>  
    <li key="2015">Duke</li>  
    <li key="2016">Villanova</li>
</ul>

現(xiàn)在陣營都知道,與關(guān)鍵元素'2014'是新的,并用鑰匙元素'2015''2016'剛剛搬進了。

在實踐中,找到一個關(guān)鍵通常并不難。您要顯示的元素可能已經(jīng)有一個唯一的ID,所以密鑰可以來自您的數(shù)據(jù):

<li key={item.id}>{item.name}</li>

如果情況并非如此,您可以將新的ID屬性添加到您的模型中,或者對內(nèi)容的某些部分進行散列以生成密鑰。關(guān)鍵只在兄弟姐妹中是唯一的,而不是全球唯一的。

作為最后的手段,您可以將項目的索引作為關(guān)鍵字傳遞給數(shù)組。如果項目從未重新排序,這可以很好地工作,但重新排序會很慢。

權(quán)衡

請務(wù)必記住,協(xié)調(diào)算法是一個實現(xiàn)細節(jié)。React可以在每一個動作上重新渲染整個應(yīng)用程序; 最終結(jié)果將是相同的。為了清楚起見,在這種情況下重申意味著要求render所有組件,但這并不意味著React將卸載并重新安裝它們。它只會按照前面章節(jié)中所述的規(guī)則來應(yīng)用差異。

我們經(jīng)常改進啟發(fā)式,以便更快地制作常見用例。在目前的實現(xiàn)中,你可以表達一個事實,即一棵子樹已經(jīng)在它的兄弟姐妹之間移動了,但是你不能說它已經(jīng)移動到別的地方了。該算法將重新渲染完整的子樹。

因為React依賴于啟發(fā)式算法,如果它們背后的假設(shè)不符合,性能將受到影響。

  1. 該算法不會嘗試匹配不同組件類型的子樹。如果您發(fā)現(xiàn)自己在輸出類似的兩種組件類型之間交替,您可能希望使它成為相同的類型。實際上,我們并未發(fā)現(xiàn)這是一個問題。

2. 密鑰應(yīng)該是穩(wěn)定的,可預測的和獨特的。不穩(wěn)定的鍵(如由那些產(chǎn)生的鍵Math.random())將導致許多組件實例和DOM節(jié)點被不必要地重新創(chuàng)建,這可能導致性能下降并丟失子組件中的狀態(tài)。

Previous article: Next article: