網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
React組件渲染后對(duì)DOM的操作
在React.js中基本不需要對(duì)DOM進(jìn)行操作,可以直接通過(guò) setState 的方式重新渲染組件,渲染的時(shí)候可以把新的 props 傳遞給子組件,從而達(dá)到頁(yè)面數(shù)據(jù)更新的效果。
但是有的時(shí)候需要組件渲染完后對(duì)DOM進(jìn)行一些操作,比如表單提交后對(duì)其中的<input>
中的內(nèi)容進(jìn)行清空,重新定義鼠標(biāo)焦點(diǎn),下面以1個(gè)簡(jiǎn)單的例子進(jìn)行說(shuō)明。
先看下顯示效果
在上例中,組件渲染結(jié)束后,清空了文本輸入框中的內(nèi)容,并重新把鼠標(biāo)焦點(diǎn)focus在文本框中,React.js 提供了 ref 屬性來(lái)幫助我們獲取已經(jīng)掛載的元素的 DOM 節(jié)點(diǎn),你可以給某個(gè) JSX 元素加上 ref屬性(本例中給<input>
加上了ref屬性),這個(gè)ref屬性值是一個(gè)回調(diào)函數(shù)。
當(dāng) input 元素在頁(yè)面上掛載完成以后,React.js 就會(huì)調(diào)用這個(gè)函數(shù),并且把這個(gè)掛載以后的 DOM 節(jié)點(diǎn)傳給這個(gè)函數(shù)。在函數(shù)中我們把這個(gè) DOM 元素設(shè)置為組件實(shí)例的一個(gè)屬性,這樣以后我們就可以通過(guò) this.input 獲取到這個(gè) DOM 元素。
然后我們可以在setNewColor()函數(shù)中調(diào)用this.input.value和this.input.focus,實(shí)現(xiàn)清空文本框輸入內(nèi)容,重新focus鼠標(biāo)焦點(diǎn)的操作。
關(guān)鍵代碼如下:給<input>
增加ref屬性,這樣通過(guò)this.input獲取input這個(gè)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 } ); } //點(diǎn)擊按鈕后事件 setNewColor(e) { this.setState({ bgColor: this.state.color }); //設(shè)置完背景顏色后,清空輸入框內(nèi)容,重新獲得焦點(diǎn) this.input.value = ""; this.input.focus(); //阻止默認(rèn)行為 e.preventDefault(); } render() { const squareStyle = { //如果是this.state.color,直接顯示顏色,不需要點(diǎn)擊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)過(guò)babel編譯成React.createElement的表達(dá)式。element在React里,是組成虛擬DOM 樹(shù)的節(jié)點(diǎn),用來(lái)描述在瀏覽器上看到什么。它的參數(shù)有三個(gè):
1、type -> 標(biāo)簽
2、attributes -> 標(biāo)簽屬性,沒(méi)有的話,可以為null
3、children -> 標(biāo)簽的子節(jié)點(diǎn)
e.g.return( React.createElement( ‘div', { className: ‘first' }, 'Hello, world' ), )
React.createElement的表達(dá)式會(huì)在render函數(shù)被調(diào)用的時(shí)候執(zhí)行。當(dāng)render函數(shù)被調(diào)用的時(shí)候,會(huì)返回一個(gè)element,element不一定是Object類(lèi)型。
element如何轉(zhuǎn)化成真實(shí)DOM節(jié)點(diǎn)的
首次渲染:
若不是Oobject類(lèi)型,string、number創(chuàng)建ReactDOMTextComponent對(duì)象,調(diào)用該對(duì)象的mount方法。在這個(gè)mount方法中,把文本放到一個(gè)span中,調(diào)用容器組件的innerHTML,進(jìn)行渲染;null、false創(chuàng)建ReactDOMEmptyComponent對(duì)象。
element為Object類(lèi)型,若是原生DOM標(biāo)簽,給它創(chuàng)建ReactDOMComponent的實(shí)例對(duì)象,通過(guò)遞歸調(diào)用到ReactDOMComponent的mountComponent方法來(lái)得到真實(shí)DOM。
如果第二步render出來(lái)的element 類(lèi)型是自定義組件
它就會(huì)去調(diào)用ReactCompositeComponentWrapper的mountComponent方法,從而形成了一個(gè)遞歸。遞歸調(diào)用子組件的render方法進(jìn)而調(diào)用map方法,直至把自定義標(biāo)簽分解為前兩種標(biāo)簽。
更新渲染:
函數(shù)setState被調(diào)用后,將傳入的state放進(jìn)pendingState的數(shù)組里存起來(lái),若當(dāng)前流程處于批量更新,則將當(dāng)前組件的instance放進(jìn)dirtyComponent里,當(dāng)這個(gè)更新流程中所有需要更新的組件收集完畢之后就會(huì)遍歷uptateComponent對(duì)組件進(jìn)行更新。當(dāng)然,如果當(dāng)前不處于批量更新的狀態(tài),會(huì)直接去遍歷dirtyComponent進(jìn)行更新。
假設(shè)Example是自定義組件,即調(diào)用的是ReactCompositeComponentWrapper的updateComponent方法。
1、計(jì)算出nextState(shouldComponentUpdate)
2、render()得到nextRenderElement(componentWillUpdate可修改state)
3、與prevtElement進(jìn)行Diff 比較,更新節(jié)點(diǎn) (componentDidUpdate)?
擴(kuò)充:diff算法
兩個(gè)相同的組件產(chǎn)生類(lèi)似的DOM結(jié)構(gòu),不同組件產(chǎn)生不同DOM結(jié)構(gòu);
對(duì)于同一層次的一組子節(jié)點(diǎn),它們可以通過(guò)唯一的id區(qū)分。
- 不同節(jié)點(diǎn)類(lèi)型:React將不會(huì)在去對(duì)比子節(jié)點(diǎn)。因?yàn)椴煌慕M件DOM結(jié)構(gòu)會(huì)不相同,所以就沒(méi)有必要在去對(duì)比子節(jié)點(diǎn)了。
- 相同節(jié)點(diǎn)類(lèi)型:dom類(lèi)型節(jié)點(diǎn),react會(huì)對(duì)比它們的屬性,只改變需要改變的屬性;自定義節(jié)點(diǎn)類(lèi)型邏輯都在React組件里面,所以它能做的就是根據(jù)新節(jié)點(diǎn)的props去更新原來(lái)根節(jié)點(diǎn)的組件實(shí)例,觸發(fā)一個(gè)更新的過(guò)程,最后在對(duì)所有的child節(jié)點(diǎn)在進(jìn)行diff的遞歸比較更新;
- 子節(jié)點(diǎn)比較:依次比較,順序不同即使仍存在的節(jié)點(diǎn)依舊會(huì)被卸載重建,可以加null保持DOM結(jié)構(gòu)的穩(wěn)定性,也可以給節(jié)點(diǎn)配置key,讓React可以識(shí)別節(jié)點(diǎn)是否存在,只在指定位置創(chuàng)建節(jié)點(diǎn)插入。
總結(jié)
原文鏈接:https://blog.csdn.net/qq_34307801/article/details/88547905
相關(guān)推薦
- 2022-04-08 pytorch?plt.savefig()的用法及保存路徑_python
- 2022-11-03 Python?頁(yè)面解析Beautiful?Soup庫(kù)的使用方法_python
- 2022-12-23 C++類(lèi)成員函數(shù)中的名字查找問(wèn)題_C 語(yǔ)言
- 2022-06-18 Android使用廣播發(fā)送消息_Android
- 2022-11-09 Python數(shù)據(jù)庫(kù)sqlite3圖文實(shí)例詳解_python
- 2022-11-27 詳解C++中動(dòng)態(tài)內(nèi)存管理和泛型編程_C 語(yǔ)言
- 2022-10-05 Redis實(shí)現(xiàn)數(shù)據(jù)的交集、并集、補(bǔ)集的示例_Redis
- 2022-07-19 Linux bond模式工作模式與原理
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支