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

React中操做Dom的四種方式

  1. 經過‘Refs’操做非受控組件《使用Ref》
  2. 經過事件處理器的默認參數event,獲取EventTarget《React事件系統》
  3. 經過原生JavaScriptDom選擇器
  4. 經過Dom操做插件,例如Jquery《React集成第三方庫》

爲何要操做Dom

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

而在典型的React數據流中,props是父組件與子組件交互的惟一方式(單向數據流)。因此,爲了修改子組件,你須要傳遞新的props去從新渲染它。react

然而,在某些狀況下,咱們須要脫離對React數據流動的依賴,去強制修改子組件。這些被修改的子組件,多是一個React組件實例,也多是實際的Dom元素。算法

Dom操做能夠直接將改變呈如今當前document,而不會促使組件更新,不會致使周期函數的調用(特殊狀況,Ref引用類組件實例)。可是,當組件更新時,這些操做也會參與「差分算法」dom

Refs即是在這些狀況下,React提供的推薦解決方式。值得注意的是,像event.targetdom選擇器dom操做插件也是可以使用的方式,可是它們存在侷限性,好比:函數

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

Refs既可以操做實際Dom元素,又可以操做React組件實例(注意:class組件能夠被使用,而function無狀態組件不能被使用,由於它沒法被實例化)動畫


何時操做Dom

這裏有一些典型的使用狀況:.net

  • 焦點獲取、文本選擇、媒體播放等動態行爲;
  • 觸發強制動畫;
  • 集成第三方庫;

對於任何可聲明性完成的事情避免使用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是無心義的。
相關文章
相關標籤/搜索