在React的渲染模式中key值的管理

Key 值維護(hù)

至此我們實現(xiàn)了一套簡單的Immutable Delta+Iterator來處理更新,這種時候我們就可以借助不可變的方式來實現(xiàn)React視圖的更新,那么在React的渲染模式中,key值的管理也是個值的探討的問題。

在這里我們就可以根據(jù)狀態(tài)不可變來生成key值,借助WeakMap映射關(guān)系獲取對應(yīng)的字符串id值,此時就可以借助key的管理以及React.memo來實現(xiàn)視圖的復(fù)用。其實在這里初步看起來key值應(yīng)該是需要主動控制強(qiáng)制刷新的時候,以及完全是新節(jié)點才會用得到的。

但是這種方式也是有問題的,因為此時我們即使輸入簡單的內(nèi)容,也會導(dǎo)致整個行的key發(fā)生改變,而此時我們是不必要更新此時的key的。因此key值是需要單獨(dú)維護(hù)的,不能直接使用不可變的對象來索引key值,那么如果是直接使用index作為key值的話,就會存在潛在的原地復(fù)用問題。

key值原地復(fù)用會導(dǎo)致組件的狀態(tài)被錯誤保留,例如此時有個非受控管理的input組件列表,在某個輸入框內(nèi)已經(jīng)輸入了內(nèi)容,當(dāng)其發(fā)生順序變化時,原始輸入內(nèi)容會跟隨著原地復(fù)用的策略留在原始的位置,而不是跟隨到新的位置,因為其整體列表順序key未發(fā)生變化導(dǎo)致React直接復(fù)用節(jié)點。

在LineState節(jié)點的key值維護(hù)中,如果是初始值則是根據(jù)state引用自增的值,在變更的時候則是盡可能地復(fù)用原始行的key,這樣可以避免過多的行節(jié)點重建并且可以控制整行的強(qiáng)制刷新。

而對于LeafState節(jié)點的key值最開始是直接使用index值,這樣實際上會存在隱性的問題,而如果直接根據(jù)Immutable來生成key值的話,任何文本內(nèi)容的更改都會導(dǎo)致key值改變進(jìn)而導(dǎo)致DOM節(jié)點的頻繁重建。

通常使用index作為key是可行的,然而在一些非受控場景下則會由于原地復(fù)用造成渲染問題,diff算法導(dǎo)致的性能問題我們暫時先不考慮。在下面的例子中我們可以看出,每次我們都是從數(shù)組頂部刪除元素,而實際的input值效果表現(xiàn)出來則是刪除了尾部的元素,這就是原地復(fù)用的問題。在非受控場景下比較明顯,而我們的ContentEditable組件就是一個非受控場景,因此這里的key值需要再考慮一下。

考慮到先前提到的我們不希望任何文本內(nèi)容的更改都導(dǎo)致key值改變引發(fā)重建,因此就不能直接使用計算的immutable對象引用來處理key值,而描述單個op的方法除了insert就只剩下attributes了。

但是如果基于attributes來獲得就需要精準(zhǔn)控制合并insert的時候取需要取舊的對象引用,且沒有屬性的op就不好處理了,因此這里可能只能將其轉(zhuǎn)為字符串處理,但是這樣同樣不能保持key的完全穩(wěn)定,因此前值的索引改變就會導(dǎo)致后續(xù)的值出現(xiàn)變更。

在slate中我先前認(rèn)為生成的key跟節(jié)點是完全一一對應(yīng)的關(guān)系,例如當(dāng)A節(jié)點變化時,其代表的層級key必然會發(fā)生變化。然而在關(guān)注這個問題之后,我發(fā)現(xiàn)其在更新生成新的Node之后,會同步更新Path以及PathRef對應(yīng)的Node節(jié)點所對應(yīng)的key值。

在后續(xù)觀察Lexical實現(xiàn)的選區(qū)模型時,發(fā)現(xiàn)其是用key值唯一地標(biāo)識每個葉子結(jié)點的,選區(qū)也是基于key值來描述的。整體表達(dá)上比較類似于Slate的選區(qū)結(jié)構(gòu),或者說是DOM樹的結(jié)構(gòu)。這里僅僅是值得Range選區(qū),Lexical實際上還有其他三種選區(qū)類型。

在這里比較重要的是key值變更時的狀態(tài)保持,因為編輯器的內(nèi)容實際上是需要編輯的。然而如果做到immutable話,很明顯直接根據(jù)狀態(tài)對象的引用來映射key會導(dǎo)致整個編輯器DOM無效的重建。例如調(diào)整標(biāo)題的等級,就由于整個行key的變化導(dǎo)致整行重建。

那么如何盡可能地復(fù)用key值就成了需要研究的問題,我們的編輯器行級別的key是被特殊維護(hù)的,即實現(xiàn)了immutable以及key值復(fù)用。而目前葉子狀態(tài)的key依賴了index值,因此如果調(diào)研Lexical的實現(xiàn),同樣可以將其應(yīng)用到我們的key值維護(hù)中。

通過在playground中調(diào)試可以發(fā)現(xiàn),即使我們不能得知其是否為immutable的實現(xiàn),依然可以發(fā)現(xiàn)Lexical的key是以一種偏左的方式維護(hù)。因此在我們的編輯器實現(xiàn)中,也可以借助同樣的方式,合并直接以左值為準(zhǔn)復(fù)用,拆分時若以0起始直接復(fù)用,起始非0則創(chuàng)建新key。

[123456(key1)][789(bold-key2)]文本,將789的加粗取消,整段文本的key值保持為key1。

[123456789(key1)]]文本,將789這段文本加粗,左側(cè)123456文本的key值保持為key1,789則是新的key。

[123456789(key1)]]文本,將123這段文本加粗,左側(cè)123文本的key值保持為key1,456789則是新的key。

[123456789(key1)]]文本,將456這段文本加粗,左側(cè)123文本的key值保持為key1,456和789分別是新的key。

patek-tys.hljjshd.com

patek-wxs.watchsc.com

patek-tys.watchsc.com

patek-sjzs.watchsc.com

patek-hzs.ytjshd.com

patek-cds.ytjshd.com

patek-wxs.ytjshd.com

patek-hzs.hbwatch.cn

patek-wxs.hbwatch.cn

patek-hfs.hbwatch.cn

patek-tys.hbwatch.cn

patek-sjzs.gzomegawatch.com

patek-hzs.watchwx8.com

patek-hks.watchwx8.com

patek-hzs.watchwx5.com

patek-cds.watchwx5.com

patek-qds.watchwx5.com

patek-hfs.watchwx5.com

patek-hks.watchwx5.com

patek-qds.watchwd.com

patek-hks.watchwd.com

patek-qzs.watchwd.com

patek-njs.hkwatch.cn

patek-cds.hkwatch.cn

patek-qds.hkwatch.cn

patek-njs.gzomegawatch.com

patek-qds.gzomegawatch.com

patek-kms.hbwatch.cn

patek-hks.hbwatch.cn

patek-qzs.hbwatch.cn

patek-njs.watchovip.com

patek-nts.watchovip.com

patek-njs.watchlj.cn

patek-cds.watchlj.cn

patek-qds.watchlj.cn

patek-kms.watchlj.cn

patek-nts.watchlj.cn

patek-qds.watchk1.top

patek-nts.watchk1.top

patek-nns.watchk1.top

patek-njs.watchjwj.cn

patek-cds.watchjwj.cn

patek-qds.watchjwj.cn

patek-njs.watchjwi.cn

patek-qds.watchjwi.cn

patek-xas.watchjwi.cn

patek-nts.watchjwi.cn

patek-nns.watchjwi.cn

patek-njs.watchjwh.cn

patek-cqs.watchjwh.cn

因此,此時在編輯器中我們也是用類似偏左的方式維護(hù)key,由于我們需要保持immutable,所以這里的表達(dá)實際上是盡可能復(fù)用先前的key狀態(tài)。這里與LineState的key值維護(hù)方式類似,都是先創(chuàng)建狀態(tài)然后更新其key值,當(dāng)然還有很多細(xì)節(jié)的地方需要處理。

這里還存在另一個小問題,我們創(chuàng)建LeafState就立即去獲得對應(yīng)的key值,然后再考慮去復(fù)用原始的key值。這樣其實就會導(dǎo)致很多不再使用的key值被創(chuàng)建,導(dǎo)致每次更新的時候看起來key的數(shù)字差值比較大。當(dāng)然這并不影響整體的功能與性能,只是調(diào)試的時候看起來比較怪。

因此我們在這里還可以優(yōu)化這部分表現(xiàn),也就是說我們在創(chuàng)建的時候不會去立即創(chuàng)建key值,而是在初始化以及更新的時候再從外部設(shè)置其key值。這個實現(xiàn)其實跟index、offset的處理方式比較類似,我們整體在update時處理所有的相關(guān)值,且開發(fā)模式渲染時進(jìn)行了嚴(yán)格檢查。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容