前言
這次準備介紹關於react的兩個新生開發過程中時不時會犯錯或者不理解的兩個小知識點:
1. React元件為什麼需要用標籤包裹?
2. React中return為什麼加()?
React元件為什麼需要用標籤包裹?
看這樣一段程式碼:
function App() { return ( <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> ); }
結果報錯了
錯誤:JSX元素必須被一個可閉合標籤
包裹
相信不少同學剛開始學習react的時候都編寫過類似的程式碼,但大家有想過為什麼會報這樣的錯嗎?以及這樣設計的目的是什麼? 不瞭解也沒有關係,接下來讓我們一起逐步解密~
再此之前先來補充React.createElement
與JSX
的關係
React.createElement與JSX
JSX是React.createElement的語法糖
一段常見的jsx程式碼
// 部分jsx <header className="App-header"> <h1>哈嘍</h1> </header>
jsx程式碼會被編譯成React.createElement函式組成的js程式碼
在元件中,需要被渲染的內容是用React.createElement(component, props, ...children) 宣告的,而 JSX 正是React.createElement函式的語法糖,JSX 會被編譯為 React.createElement()
但瀏覽器本身不支援 JSX,所以在應用釋出上線前,JSX 原始碼需要工具編譯成由若干createElement函式組成的 JS 程式碼,然後才能在瀏覽器中正常執行。JSX 需要被編譯,而編譯這個動作就是由 Babel 來完成的。
經Babel編譯成 JS 就會變成:
React.createElement("header", {className: "App-header"}, React.createElement("h1", null, "哈嘍") );
React.createElement的基本用法
React.createElement(component, props, ...children) 接受至少三個引數:
type: 字串(代表 HTML 標籤)或 React 元件(函式元件或類元件)。
props: 物件,包含了該元素的屬性。傳遞給元素的屬性在元件中可透過 this.props 或 props 訪問。
...children: 其餘引數都會作為子節點(children)處理。這可以是更多的元素,字串,數字等。
單根節點思想
當React在處理渲染一個元件的時候,它需要每個元件返回一個單一的根節點。結合上述的程式碼,我們可以得到:
const element = ( <div> <h1>Hello CodeSandbox</h1> <h2 className='title'>Start editing to see some magic happen!</h2> </div> ) // 上述JSX最終會轉化為⬇️ const element = React.createElement( 'div', null, React.createElement('h1', null, 'Hello CodeSandbox'), React.createElement('h2', { className='title' }, 'Start editing to see some magic happen!') )
綜上所述,前言中的報錯是因為React.createElement設計時是以單節點為基礎的,所以同時傳入多個節點會發生報錯。
為什麼設計React.createElement時是以單節點為基礎的?
接下來我想請大家跟我一起設想一個場景⬇️
首先,請大家拋棄react語法,用原生JS去思考這個問題。
現在有一個列表頁,存在著3條資料,我點選了搜尋,發現當前頁面新增了4條資料,總共7條資料,這個時候你作為開發者,該怎麼去更新dom呢?
這個時候你可能脫口而出,將這4條資料一條條塞進去,但大家應該都明白,每次操作dom的效能開銷是很大的,需要進行dom插入(進行dom樹的搜尋) ,且會引起頁面的迴流重繪。如果進行多次操作,效能開銷就會成倍增長。
現在你應該想到了,那我一次性把這4條資料的dom都塞進去,不就操作一次dom了嗎?首先恭喜你回答正確,但可以再思考一下,我們怎麼做到將4個dom一次性插入呢?原生js可沒有類似的api支援你做到這一點,所以我們是不是需要將這多個dom合併成一個單一節點?這就是React的單節點思想。
所以我們之所以用標籤包裹react元件的重要原因。
React元件中return為什麼加()?
react有這麼一個規則:
例如:
function Component() { return <div>{/*假設這行JSX語句很長*/}</div>; }
放到編譯器裡會生成:
function Component() { return; React.createElement("div", null); }
發現了沒有
這都還沒走到 React.createElement
就被return了
爲了修正這個問題,我們需要為 JSX 加上括號:
function Component() { return ( <div>{/*假設這行JSX語句很長,爲了提升一些程式碼可讀性,特地換行*/}</div> ); }
再次編譯:
function Component() { return React.createElement("div", null); }
這纔是我們最終想要的效果了~
原因如下:
JavaScript會自動在每行的末尾新增分號,如果
return
語句後沒有使用括號,就會在它的末尾自動插入一個分號(;)
,從而導致語法錯誤。透過使用括號,可以確保return
語句作為一個整體被正確解析,避免因為自動插入分號而導致的bug。