?1.認(rèn)識(shí)JSX
1.1JSX是什么?
JSX是一種JavaScript的語(yǔ)法擴(kuò)展(eXtension),也在很多地方稱之為JavaScript XML,因?yàn)榭雌鹁褪且欢蝀ML語(yǔ)法;
它用于描述我們的UI界面,并且其完成可以和JavaScript融合在一起使用;
它不同于Vue中的模塊語(yǔ)法,你不需要專門(mén)學(xué)習(xí)模塊語(yǔ)法中的一些指令(比如v-for、v-if、v-else、v-bind);
1.2?為什么React選擇了JSX?
React認(rèn)為渲染邏輯本質(zhì)上與其他UI邏輯存在內(nèi)在耦合
比如UI需要綁定事件(button、a原生等等);
比如UI中需要展示數(shù)據(jù)狀態(tài),在某些狀態(tài)發(fā)生改變時(shí),又需要改變UI;
他們之間是密不可分,所以React沒(méi)有將標(biāo)記分離到不同的文件中,而是將它們組合到了一起,這個(gè)地方就是組件(Component);
當(dāng)然,后面我們還是會(huì)繼續(xù)學(xué)習(xí)更多組件相關(guān)的東西;
在這里,我們只需要知道,JSX其實(shí)是嵌入到JavaScript中的一種結(jié)構(gòu)語(yǔ)法;
2.jsx事件監(jiān)聽(tīng)
2.1通過(guò)onClick直接綁定函數(shù)(方式一)
????通過(guò)直接綁定的方式可以調(diào)用‘btnClick’函數(shù),但是會(huì)有一個(gè)弊端,無(wú)法通過(guò)this調(diào)用組件內(nèi)的狀態(tài)屬性。原因是onClick是通過(guò)React內(nèi)部調(diào)用,沒(méi)有綁定this,所以‘btnClick’函數(shù)內(nèi)的this指向‘undefine’。

2.2 通過(guò)顯示綁定方式調(diào)用(方式二)????
通過(guò)bind函數(shù)主動(dòng)綁定this可以解決btnClick內(nèi)部this指向問(wèn)題,但是方式二的弊端是有大量的重復(fù)代碼,必須需要調(diào)用this.XXX.bind(this),并且傳參也不方便。

2.3使用 ES6 class fields 語(yǔ)法(方式三)
你會(huì)發(fā)現(xiàn)我這里將btnClick的定義變成了一種賦值語(yǔ)句:
這是ES6中給類定義屬性的方法,稱之為class fields語(yǔ)法;
因?yàn)檫@里我們賦值時(shí),使用了箭頭函數(shù),所以在當(dāng)前函數(shù)中的this會(huì)去上一個(gè)作用域中查找;
而上一個(gè)作用域中的this就是當(dāng)前的對(duì)象;

2.4?事件監(jiān)聽(tīng)時(shí)傳入箭頭函數(shù)(推薦)
因?yàn)?onClick?中要求我們傳入一個(gè)函數(shù),那么我們可以直接定義一個(gè)箭頭函數(shù)傳入:
傳入的箭頭函數(shù)的函數(shù)體是我們需要執(zhí)行的代碼,我們直接執(zhí)行?this.btnClick();
this.btnClick()中通過(guò)this來(lái)指定會(huì)進(jìn)行隱式綁定,最終this也是正確的;

3.JSX轉(zhuǎn)換本質(zhì)
實(shí)際上,jsx 僅僅只是?React.createElement(component, props, ...children)?函數(shù)的語(yǔ)法糖。
所有的jsx最終都會(huì)被轉(zhuǎn)換成React.createElement的函數(shù)調(diào)用。
React.createElement在源碼的什么位置呢?

createElement需要傳遞三個(gè)參數(shù):
參數(shù)一:type
當(dāng)前ReactElement的類型;
如果是標(biāo)簽元素,那么就使用字符串表示 “div”;
如果是組件元素,那么就直接使用組件的名稱;
參數(shù)二:config
所有jsx中的屬性都在config中以對(duì)象的屬性和值的形式存儲(chǔ)
參數(shù)三:children
存放在標(biāo)簽中的內(nèi)容,以children數(shù)組的方式進(jìn)行存儲(chǔ);
當(dāng)然,如果是多個(gè)元素呢?React內(nèi)部有對(duì)它們進(jìn)行處理,處理的源碼在下方
對(duì)children進(jìn)行的處理:
從第二個(gè)參數(shù)開(kāi)始,將其他所有的參數(shù),放到props對(duì)象的children中

4. 虛擬DOM
我們通過(guò)?React.createElement?最終創(chuàng)建出來(lái)一個(gè) ReactElement對(duì)象:

這個(gè)ReactElement對(duì)象是什么作用呢?React為什么要?jiǎng)?chuàng)建它呢?
原因是React利用ReactElement對(duì)象組成了一個(gè)JavaScript的對(duì)象樹(shù);
JavaScript的對(duì)象樹(shù)就是大名鼎鼎的虛擬DOM(Virtual DOM);
如何查看ReactElement的樹(shù)結(jié)構(gòu)呢?
我們可以將之前的jsx返回結(jié)果進(jìn)行打印;
注意下面代碼中我打jsx的打??;

打印結(jié)果,在瀏覽器中查看:

而ReactElement最終形成的樹(shù)結(jié)構(gòu)就是Virtual DOM。
3.1為什么采用虛擬DOM
為什么要采用虛擬DOM,而不是直接修改真實(shí)的DOM呢?
很難跟蹤狀態(tài)發(fā)生的改變:原有的開(kāi)發(fā)模式,我們很難跟蹤到狀態(tài)發(fā)生的改變,不方便針對(duì)我們應(yīng)用程序進(jìn)行調(diào)試;
操作真實(shí)DOM性能較低:傳統(tǒng)的開(kāi)發(fā)模式會(huì)進(jìn)行頻繁的DOM操作,而這一的做法性能非常的低;
主要原因:DOM操作性能非常低:
首先,document.createElement本身創(chuàng)建出來(lái)的就是一個(gè)非常復(fù)雜的對(duì)象;
https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createElement
其次,DOM操作會(huì)引起瀏覽器的回流和重繪,所以在開(kāi)發(fā)中應(yīng)該避免頻繁的DOM操作;
虛擬DOM幫助我們從命令式編程轉(zhuǎn)到了聲明式編程的模式
React官方的說(shuō)法:Virtual DOM 是一種編程理念。
在這個(gè)理念中,UI以一種理想化或者說(shuō)虛擬化的方式保存在內(nèi)存中,并且它是一個(gè)相對(duì)簡(jiǎn)單的JavaScript對(duì)象,我們可以通過(guò)ReactDOM.render讓?虛擬DOM?和?真實(shí)DOM同步起來(lái),這個(gè)過(guò)程中叫做協(xié)調(diào)(Reconciliation);
這種編程的方式賦予了React聲明式的API:你只需要告訴React希望讓UI是什么狀態(tài),React來(lái)確保DOM和這些狀態(tài)是匹配的。
你不需要直接進(jìn)行DOM操作,只可以從手動(dòng)更改DOM、屬性操作、事件處理中解放出來(lái);