1. 程式人生 > >React中JSX的理解

React中JSX的理解

# React中JSX的理解 `JSX`是快速生成`react`元素的一種語法,實際是`React.createElement(component, props, ...children)`的語法糖,同時`JSX`也是`Js`的語法擴充套件,包含所有`Js`功能。 ## 描述 ### JSX發展過程 在之前,`Facebook`是`PHP`大戶,所以`React`最開始的靈感就來自於`PHP`。 在`2004`年這個時候,大家都還在用`PHP`的字串拼接來開發網站。 ```php $str = "
    "; foreach ($talks as $talk) { $str += "
  • " . $talk->name . "
  • "; } $str += "
"; ``` 這種方式程式碼寫出來不好看不說,還容易造成`XSS`等安全問題。應對方法是對使用者的任何輸入都進行轉義`Escape`,但是如果對字串進行多次轉義,那麼反轉義的次數也必須是相同的,否則會無法得到原內容,如果又不小心把`HTML`標籤給轉義了,那麼`HTML`標籤會直接顯示給使用者,從而導致很差的使用者體驗。 到了`2010`年,為了更加高效的編碼,同時也避免轉義`HTML`標籤的錯誤,`Facebook`開發了`XHP`。`XHP`是對`PHP`的語法拓展,它允許開發者直接在`PHP`中使用`HTML`標籤,而不再使用字串。 ```php $content =
    ; foreach ($talks as $talk) { $content->appendChild(
  • {$talk->name}
  • ); } ``` 這樣的話,所有`HTML`標籤都使用不同於`PHP`的語法,我們可以輕易的分辨哪些需要轉義哪些不需要轉義。不久的後來,`Facebook`的工程師又發現他們還可以建立自定義標籤,而且通過組合自定義標籤有助於構建大型應用。 到了`2013`年,前端工程師`Jordan Walke`向他的經理提出了一個大膽的想法:把`XHP`的拓展功能遷移到`Js`中,首要任務是需要一個拓展來讓`Js`支援`XML`語法,該拓展稱為`JSX`。因為當時由於`Node.js`在`Facebook`已經有很多實踐,所以很快就實現了`JSX`。 ```jsx const content = ( {talks.map(talk =>
    )}
    ); ``` ### 為何使用JSX `React`認為渲染邏輯本質上與其他`UI`邏輯內在耦合,比如在`UI`中需要繫結處理事件、在某些時刻狀態發生變化時需要通知到`UI`,以及需要在`UI`中展示準備好的資料。 `React`並沒有採用將標記與邏輯進行分離到不同檔案這種人為地分離方式,而是通過將二者共同存放在稱之為元件的鬆散耦合單元之中,來實現關注點分離。 `React`不強制要求使用`JSX`,但是大多數人發現,在`JavaScript`程式碼中將`JSX`和`UI`放在一起時,會在視覺上有輔助作用,它還可以使`React`顯示更多有用的錯誤和警告訊息。 簡單來說,`JSX`可以很好的描述頁面`html`結構,很方便的在`Js`中寫`html`程式碼,並具有`Js`的全部功能。 ### 優點 `JSX`的優點主要體現在以下三點: * 快速,`JSX`執行更快,因為它在編譯為`JavaScript`程式碼後進行了優化。 * 安全,與`JavaScript`相比,`JSX`是靜態型別的,大多是型別安全的。使用`JSX`進行開發時,應用程式的質量會變得更高,因為在編譯過程中會發現許多錯誤,它也提供編譯器級別的除錯功能。 * 簡單,語法簡潔,上手容易。 ## JSX例項 ### 規則定義 `JSX`中定義了一些規則以及用法: * `JSX`只能有一個根元素,`JSX`標籤必須是閉合的,如果沒有內容可以寫成自閉和的形式``。 * 可以在`JSX`通過`{}`嵌入`Js`表示式。 * `JSX`會被`babel`轉換成`React.createElement`的函式呼叫,呼叫後會建立一個描述`HTML`資訊的`Js`物件。 * `JSX`中的子元素可以為字串字面量。 * `JSX`中的子元素可以為`JSX`元素。 * `JSX`中的子元素可以為儲存在陣列中的一組元素。 * `JSX`中的子元素可以為`Js`表示式,可與其他型別子元素混用;可用於展示任意長度的列表。 * `JSX`中的子元素可以為函式及函式呼叫。 * `JSX`中的子元素如果為`boolean/null/undefined`將會被忽略,如果使用`&&`運算子,需要確保前面的是布林值,如果是`0/1`則會被渲染出來。 * 在物件屬性中定義`React`元件,可以使用`object`的點語法使用該元件。 * `React`元素會被轉換為呼叫`React.createElement`函式,引數是元件,因此`React`和該元件必須在作用域內。 * `React`元素需要大寫字母開頭,或者將元素賦值給大小字母開頭的變數,小寫字母將被認為是`HTML`標籤。 * 不能使用表示式作為`React`元素型別,需要先將其賦值給大寫字母開頭的變數,再把該變數作為元件。 ### JSX的使用 在示例中我們聲明瞭一個名為`name`的變數,然後在`JSX`中使用它,並將它包裹在大括號中。在`JSX`語法中,可以在大括號內放置任何有效的`JavaScript`表示式。例如`2 + 2`、`user.firstName`或`formatName(user)`都是有效的`JavaScript`表示式。 ```jsx const name = "Josh Perez"; const element =

    Hello, {name}

    ; ReactDOM.render( element, document.getElementById("root") ); ``` 同樣`JSX`也是一個表示式,`JSX`天生就是需要被編譯之後才可以使用的,在編譯之後`JSX`表示式會被轉為普通`JavaScript`函式呼叫,並且對其取值後得到`JavaScript`物件。也就是說,你可以在`if`語句和`for`迴圈的程式碼塊中使用`JSX`,將`JSX`賦值給變數,把`JSX`當作引數傳入,以及從函式中返回`JSX`。 ```jsx function getGreeting(user) { if (user) { return

    Hello, {formatName(user)}!

    ; } return

    Hello, Stranger.

    ; } ``` 通常可以通過使用引號來將屬性值指定為字串字面量,也可以使用大括號來在屬性值中插入一個`JavaScript`表示式,在屬性中嵌入`JavaScript`表示式時,不要在大括號外面加上引號。因為`JSX`語法上更接近`JavaScript`而不是`HTML`,所以`React DOM`使用`camelCase`小駝峰命名來定義屬性的名稱,而不使用`HTML`屬性名稱的命名約定。例如`JSX`裡的`class`變成了`className`,而`tabindex`則變為`tabIndex`。 ```jsx const element1 = ; const element2 = ; ``` `JSX`中也可以使用``來閉合標籤,另外`JSX`同樣也可以直接定義很多子元素。 ```jsx const element1 = ; const element2 = (

    Hello!

    Good to see you here.

    ); ``` 你可以安全地在`JSX`當中插入使用者輸入內容,`React DOM`在渲染所有輸入內容之前,預設會進行轉義,這樣可以確保在你的應用中,永遠不會注入那些並非自己明確編寫的內容,所有的內容在渲染之前都被轉換成了字串,可以有效地防止 `XSS`跨站指令碼攻擊。 ```jsx const title = response.potentiallyMaliciousInput; // 直接使用是安全的: const element =

    {title}

    ; ``` 實際上`Babel`會把`JSX`轉譯成一個名為`React.createElement()`函式呼叫,通過`React.createElement()`定義的元素與使用`JSX`生成的元素相同,同樣這就使得`JSX`天生就是需要編譯的。 ```jsx const element1 = (

    Hello, world!

    ); // 等價 const element2 = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' ); ``` `React.createElement()`會預先執行一些檢查,以幫助你編寫無錯程式碼,但實際上它建立了一個這樣的物件。這些物件被稱為`React 元素`,它們描述了你希望在螢幕上看到的內容,`React`通過讀取這些物件,然後使用它們來構建`DOM`以及保持隨時更新。 ```jsx // 注意:這是簡化過的結構 const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' } }; ``` 實際上,這就是虛擬`DOM`的一個節點,`Virtual DOM`是一種程式設計概念,在這個概念裡,`UI`以一種理想化的,或者說虛擬的表現形式被保存於記憶體中,並通過如`ReactDOM`等類庫使之與真實的`DOM`同步,這一過程叫做協調。這種方式賦予了`React`宣告式的`API`,您告訴`React`希望讓`UI`是什麼狀態,`React`就確保`DOM`匹配該狀態,這樣可以從屬性操作、事件處理和手動`DOM`更新這些在構建應用程式時必要的操作中解放出來。 與其將`Virtual DOM`視為一種技術,不如說它是一種模式,人們提到它時經常是要表達不同的東西。在`React`的世界裡,術語`Virtual DOM`通常與`React`元素關聯在一起,因為它們都是代表了使用者介面的物件,而`React`也使用一個名為`fibers`的內部物件來存放元件樹的附加資訊,上述二者也被認為是`React`中`Virtual DOM` 實現的一部分,`Virtual DOM`也為使用`diff`演算法奠定了基礎。 ```html

    1

    11 ``` ```javascript // 使用Js物件去描述上述節點以及文件 { type: "tag", tagName: "div", attr: { className: "root" name: "root" }, parent: null, children: [{ type: "tag", tagName: "p", attr: {}, parent: {} /* 父節點的引用 */, children: [{ type: "text", tagName: "text", parent: {} /* 父節點的引用 */, content: "1" }] },{ type: "tag", tagName: "div", attr: {}, parent: {} /* 父節點的引用 */, children: [{ type: "text", tagName: "text", parent: {} /* 父節點的引用 */, content: "11" }] }] } ``` ### 示例 ```html JSX示例 ``` ## 每日一題 ``` https://github.com/WindrunnerMax/EveryDay ``` ## 參考 ``` https://www.zhihu.com/question/265784392 https://juejin.cn/post/6844904127013584904 https://zh-hans.reactjs.org/docs/introducing-jsx.html ```