React組件渲染后對DOM的操作方式
React組件渲染后對DOM的操作
在React.js中基本不需要對DOM進行操作,可以直接通過 setState 的方式重新渲染組件,渲染的時候可以把新的 props 傳遞給子組件,從而達到頁面數(shù)據(jù)更新的效果。
但是有的時候需要組件渲染完后對DOM進行一些操作,比如表單提交后對其中的<input>
中的內(nèi)容進行清空,重新定義鼠標焦點,下面以1個簡單的例子進行說明。
先看下顯示效果
在上例中,組件渲染結(jié)束后,清空了文本輸入框中的內(nèi)容,并重新把鼠標焦點focus在文本框中,React.js 提供了 ref 屬性來幫助我們獲取已經(jīng)掛載的元素的 DOM 節(jié)點,你可以給某個 JSX 元素加上 ref屬性(本例中給<input>
加上了ref屬性),這個ref屬性值是一個回調(diào)函數(shù)。
當 input 元素在頁面上掛載完成以后,React.js 就會調(diào)用這個函數(shù),并且把這個掛載以后的 DOM 節(jié)點傳給這個函數(shù)。在函數(shù)中我們把這個 DOM 元素設(shè)置為組件實例的一個屬性,這樣以后我們就可以通過 this.input 獲取到這個 DOM 元素。
然后我們可以在setNewColor()函數(shù)中調(diào)用this.input.value和this.input.focus,實現(xiàn)清空文本框輸入內(nèi)容,重新focus鼠標焦點的操作。
關(guān)鍵代碼如下:給<input>
增加ref屬性,這樣通過this.input獲取input這個DOM元素,并調(diào)用相應(yīng)的API。
<input ref={(input) => this.input = input} placeholder={"Please enter a color"} onChange={e => this.colorValue(e)} />
完整代碼如下
class Color extends React.Component { constructor(props) { super(props); this.state = { color: '', bgColor: '' }; } //獲取文本框中用戶輸入的內(nèi)容 colorValue(e) { this.setState({ color: e.target.value } ); } //點擊按鈕后事件 setNewColor(e) { this.setState({ bgColor: this.state.color }); //設(shè)置完背景顏色后,清空輸入框內(nèi)容,重新獲得焦點 this.input.value = ""; this.input.focus(); //阻止默認行為 e.preventDefault(); } render() { const squareStyle = { //如果是this.state.color,直接顯示顏色,不需要點擊show按鈕 backgroundColor: this.state.bgColor, }; return ( <div className={"colorArea"}> <div className={"colorSquare"} style={squareStyle}></div> <form onSubmit={e => this.setNewColor(e)}> <input ref={(input) => this.input = input} placeholder={"Please enter a color"} onChange={e => this.colorValue(e)}/> <button type={"submit"}>show</button> </form> </div> ); } } if (document.getElementById('container')) { ReactDOM.render( <div> <Color/> </div>, document.getElementById('container') ); }
React組件渲染原理
jsx如何生成element
JSX代碼經(jīng)過babel編譯成React.createElement的表達式。element在React里,是組成虛擬DOM 樹的節(jié)點,用來描述在瀏覽器上看到什么。它的參數(shù)有三個:
1、type -> 標簽
2、attributes -> 標簽屬性,沒有的話,可以為null
3、children -> 標簽的子節(jié)點
e.g.return( React.createElement( ‘div', { className: ‘first' }, 'Hello, world' ), )
React.createElement的表達式會在render函數(shù)被調(diào)用的時候執(zhí)行。當render函數(shù)被調(diào)用的時候,會返回一個element,element不一定是Object類型。
element如何轉(zhuǎn)化成真實DOM節(jié)點的
首次渲染:
若不是Oobject類型,string、number創(chuàng)建ReactDOMTextComponent對象,調(diào)用該對象的mount方法。在這個mount方法中,把文本放到一個span中,調(diào)用容器組件的innerHTML,進行渲染;null、false創(chuàng)建ReactDOMEmptyComponent對象。
element為Object類型,若是原生DOM標簽,給它創(chuàng)建ReactDOMComponent的實例對象,通過遞歸調(diào)用到ReactDOMComponent的mountComponent方法來得到真實DOM。
如果第二步render出來的element 類型是自定義組件
它就會去調(diào)用ReactCompositeComponentWrapper的mountComponent方法,從而形成了一個遞歸。遞歸調(diào)用子組件的render方法進而調(diào)用map方法,直至把自定義標簽分解為前兩種標簽。
更新渲染:
函數(shù)setState被調(diào)用后,將傳入的state放進pendingState的數(shù)組里存起來,若當前流程處于批量更新,則將當前組件的instance放進dirtyComponent里,當這個更新流程中所有需要更新的組件收集完畢之后就會遍歷uptateComponent對組件進行更新。當然,如果當前不處于批量更新的狀態(tài),會直接去遍歷dirtyComponent進行更新。
假設(shè)Example是自定義組件,即調(diào)用的是ReactCompositeComponentWrapper的updateComponent方法。
1、計算出nextState(shouldComponentUpdate)
2、render()得到nextRenderElement(componentWillUpdate可修改state)
3、與prevtElement進行Diff 比較,更新節(jié)點 (componentDidUpdate)?
擴充:diff算法
兩個相同的組件產(chǎn)生類似的DOM結(jié)構(gòu),不同組件產(chǎn)生不同DOM結(jié)構(gòu);
對于同一層次的一組子節(jié)點,它們可以通過唯一的id區(qū)分。
- 不同節(jié)點類型:React將不會在去對比子節(jié)點。因為不同的組件DOM結(jié)構(gòu)會不相同,所以就沒有必要在去對比子節(jié)點了。
- 相同節(jié)點類型:dom類型節(jié)點,react會對比它們的屬性,只改變需要改變的屬性;自定義節(jié)點類型邏輯都在React組件里面,所以它能做的就是根據(jù)新節(jié)點的props去更新原來根節(jié)點的組件實例,觸發(fā)一個更新的過程,最后在對所有的child節(jié)點在進行diff的遞歸比較更新;
- 子節(jié)點比較:依次比較,順序不同即使仍存在的節(jié)點依舊會被卸載重建,可以加null保持DOM結(jié)構(gòu)的穩(wěn)定性,也可以給節(jié)點配置key,讓React可以識別節(jié)點是否存在,只在指定位置創(chuàng)建節(jié)點插入。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
React Hook 父子組件相互調(diào)用函數(shù)方式
這篇文章主要介紹了React Hook 父子組件相互調(diào)用函數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09react中useState使用:如何實現(xiàn)在當前表格直接更改數(shù)據(jù)
這篇文章主要介紹了react中useState的使用:如何實現(xiàn)在當前表格直接更改數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08解決React報錯You provided a `checked` prop&n
這篇文章主要為大家介紹了React報錯You provided a `checked` prop to a form field的解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12ReactNative 之FlatList使用及踩坑封裝總結(jié)
本篇文章主要介紹了ReactNative 之FlatList使用及踩坑封裝總結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11解決React報錯Unexpected default export of an
這篇文章主要為大家介紹了React報錯Unexpected default export of anonymous function解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12