1. 程式人生 > >React踩坑筆記 —— React中的Dom操作

React踩坑筆記 —— React中的Dom操作

目錄


React中操作Dom的四種方式

  1. 通過‘Refs’操作非受控元件《使用Ref》
  2. 通過事件處理器的預設引數event,獲取EventTarget《React事件系統》
  3. 通過原生JavaScriptDom選擇器
  4. 通過Dom操作外掛,例如Jquery《React整合第三方庫》

為什麼要操作Dom

在一般的網頁應用中,像使用原生JavaScript、Jquery開發的應用中,Dom操作是很常見的。

而在典型的React資料流中,props是父元件與子元件互動的唯一方式(單向資料流)。所以,為了修改子元件,你需要傳遞新的props去重新渲染它。

然而,在某些情況下,我們需要脫離對React資料流動的依賴,去強制修改子元件。這些被修改的子元件,可能是一個React元件例項,也可能是實際的Dom元素。

Refs便是在這些情況下,React提供的推薦解決方式。值得注意的是,像event.targetdom選擇器dom操作外掛也是能夠使用的方式,但是它們存在侷限性,比如:

  • 只能夠操作實際Dom元素;
  • 相同元件可以被多次渲染,id選擇器無法正常工作。

Refs

既能夠操作實際Dom元素,又能夠操作React元件例項(注意:class元件可以被使用,而function無狀態元件不能被使用,因為它無法被例項化)


什麼時候操作Dom

這裡有一些典型的使用情況:

  • 焦點獲取、文字選擇、媒體播放等動態行為;
  • 觸發強制動畫;
  • 整合第三方庫;

對於任何可宣告性完成的事情避免使用Refs 例如,在Dialog元件中通過傳遞isOpen屬性,來代替暴露open()close()方法。


須知

  • React不會知道React以外的方式對Dom做出的改變,它基於自己內部的表現來決定如何更新,如果一個Dom節點同時被React以外的方式操作,那麼React將變的混亂,並且無從恢復。
    • 比如:用React以外的方式對Dom內容修改,在props或state發生改變——元件更新後被覆蓋;
    • 比如:用React以外的方式對Dom內容的修改依賴於元件更新前的狀態,元件更新後沒有達到預期效果;
  • 為了解決這個問題,你可以通過狀態改變來記錄每一步操作,以便在更新後重現它。
  • 最乾脆的方式就是,不讓React有理由去更新這個Dom,從而阻止元件更新帶來的衝突。例如空的<div />,這個<div />不需要propsstate的支撐,所以React沒有理由去更新它,可以留給Dom操作外掛選擇器自由的管理這部分Dom。
  • 記得在元件解除安裝時移除外掛註冊的事件監聽,避免記憶體洩漏。
  • 另外,React推薦使用RefsReact event system來操作Dom,最好不要依賴ID選擇器,因為相同的元件可能會被多次渲染,使得整個document中存在多個元素具有相同id屬性。(詳情可見《document中id屬性不唯一時,id選擇器如何工作》

注意

  • 在Props和State發生改變的時候,元件會發生更新,至於最終如何被更新,可以檢視《差分演算法》
  • document維護著整棵React元素樹,“差分演算法” 便是基於document比較React元素樹或元素子樹的演算法;
  • 通過Refsevent.targetdom選擇器Dom操作外掛對Dom節點的操作將儲存在document中,並參與 “差分演算法”,然而:
    • 元件更新將會對該元件對應的React元素子樹執行差異演算法,如果新的狀態和屬性沒有影響到這些Dom操作,那麼操作將被保留,否則對Dom的操作會消失變得混亂
    • 元件解除安裝(路由),將會解除安裝元件,同時所包含的Dom節點會被銷燬、子元件也會被解除安裝,所以之前對Dom的操作也會消失(除非你專門記錄它:可以使用父元件statestorage
    • 頁面重新整理將會產生新的document,之前對Dom的操作將會消失(除非你專門記錄它:只能使用storage)。
  • Element被建立後,被諸如Node.insertBefore()之類的操作插入document之前,是沒有意義的,通過選擇器document.querySelector()document.getElementById()只能獲得null,所以在document渲染完成前,操作Dom是無意義的。