使用 JSX 描述 UI 信息

這一節咱們經過一個簡單的例子講解 React.js 描述頁面 UI 的方式。把 src/index.js 中的代碼改爲:css

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'

class Header extends Component {
  render () {
    return (
      <div>
        <h1>React 小書</h1>
      </div>
    )
  }
}

ReactDOM.render(
  <Header />,
  document.getElementById('root')
)

咱們在文件頭部從 react 的包當中引入了 React 和 React.js 的組件父類 Component。記住,只要你要寫 React.js 組件,那麼就必需要引入這兩個東西。html

ReactDOM 能夠幫助咱們把 React 組件渲染到頁面上去,沒有其它的做用了。你能夠發現它是從 react-dom 中引入的,而不是從 react 引入。有些朋友可能會疑惑,爲何不把這些東西都包含在 react 包當中呢?咱們稍後會回答這個問題。react

接下來的代碼你看起來會比較熟悉,但又會有點陌生。你看其實它跟咱們前幾節裏面講的內容其實很相似,一個組件繼承 Component 類,有一個 render 方法,而且把這個組件的 HTML 結構返回;這裏 return 的東西就比較奇怪了,它並非一個字符串,看起來像是純 HTML 代碼寫在 JavaScript 代碼裏面。你也許會說,這不就有語法錯誤了麼?這徹底不是合法的 JavaScript 代碼。這種看起來「在 JavaScript 寫的標籤的」語法叫 JSX。算法

JSX 原理

爲了讓你們深入理解 JSX 的含義。有必要簡單介紹了一下 JSX 稍微底層的運做原理,這樣你們能夠更加深入理解 JSX 究竟是什麼東西,爲何要有這種語法,它是通過怎麼樣的轉化變成頁面的元素的。canvas

思考一個問題:如何用 JavaScript 對象來表現一個 DOM 元素的結構,舉個例子:瀏覽器

<div class='box' id='content'>
  <div class='title'>Hello</div>
  <button>Click</button>
</div>

每一個 DOM 元素的結構均可以用 JavaScript 的對象來表示。你會發現一個 DOM 元素包含的信息其實只有三個:標籤名,屬性,子元素。app

因此其實上面這個 HTML 全部的信息咱們均可以用合法的 JavaScript 對象來表示:dom

{
  tag: 'div',
  attrs: { className: 'box', id: 'content'},
  children: [
    {
      tag: 'div',
      arrts: { className: 'title' },
      children: ['Hello']
    },
    {
      tag: 'button',
      attrs: null,
      children: ['Click']
    }
  ]
}

你會發現,HTML 的信息和 JavaScript 所包含的結構和信息實際上是同樣的,咱們能夠用 JavaScript 對象來描述全部能用 HTML 表示的 UI 信息。可是用 JavaScript 寫起來太長了,結構看起來又不清晰,用 HTML 的方式寫起來就方便不少了。性能

因而 React.js 就把 JavaScript 的語法擴展了一下,讓 JavaScript 語言可以支持這種直接在 JavaScript 代碼裏面編寫相似 HTML 標籤結構的語法,這樣寫起來就方便不少了。編譯的過程會把相似 HTML 的 JSX 結構轉換成 JavaScript 的對象結構。優化

上面的代碼:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'

class Header extends Component {
  render () {
    return (
      <div>
        <h1 className='title'>React 小書</h1>
      </div>
    )
  }
}

ReactDOM.render(
  <Header />,
  document.getElementById('root')
)

通過編譯之後會變成:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'

class Header extends Component {
  render () {
    return (
     React.createElement(
        "div",
        null,
        React.createElement(
          "h1",
          { className: 'title' },
          "React 小書"
        )
      )
    )
  }
}

ReactDOM.render(
  React.createElement(Header, null), 
  document.getElementById('root')
);

React.createElement 會構建一個 JavaScript 對象來描述你 HTML 結構的信息,包括標籤名、屬性、還有子元素等。這樣的代碼就是合法的 JavaScript 代碼了。因此使用 React 和 JSX 的時候必定要通過編譯的過程。

這裏再重複一遍:所謂的 JSX 其實就是 JavaScript 對象。每當在 JavaScript 代碼中看到這種 JSX 結構的時候,腦子裏面就能夠自動作轉化,這樣對你理解 React.js 的組件寫法頗有好處。

有了這個表示 HTML 結構和信息的對象之後,就能夠拿去構造真正的 DOM 元素,而後把這個 DOM 元素塞到頁面上。這也是咱們最後一段代碼中 ReactDOM.render 所幹的事情:

ReactDOM.render(
  <Header />,
  document.getElementById('root')
)

ReactDOM.render 功能就是把組件渲染而且構造 DOM 樹,而後插入到頁面上某個特定的元素上(在這裏是 id 爲 root 的 div 元素)。

因此能夠總結一下從 JSX 到頁面到底通過了什麼樣的過程:

有些同窗可能會問,爲何不直接從 JSX 直接渲染構造 DOM 結構,而是要通過中間這麼一層呢?

第一個緣由是,當咱們拿到一個表示 UI 的結構和信息的對象之後,不必定會把元素渲染到瀏覽器的普通頁面上,咱們有可能把這個結構渲染到 canvas 上,或者是手機 App 上。因此這也是爲何會要把 react-dom 單獨抽離出來的緣由,能夠想象有一個叫 react-canvas 能夠幫咱們把 UI 渲染到 canvas 上,或者是有一個叫 react-app 能夠幫咱們把它轉換成原生的 App(實際上這玩意叫 ReactNative)。

第二個緣由是,有了這樣一個對象。當數據變化,須要更新組件的時候,就能夠用比較快的算法操做這個 JavaScript 對象,而不用直接操做頁面上的 DOM,這樣能夠儘可能少的減小瀏覽器重排,極大地優化性能。這個在之後的章節中咱們會提到。

總結

要記住幾個點:

  1. JSX 是 JavaScript 語言的一種語法擴展,長得像 HTML,但並非 HTML。
  2. React.js 能夠用 JSX 來描述你的組件長什麼樣的。
  3. JSX 在編譯的時候會變成相應的 JavaScript 對象描述。
  4. react-dom 負責把這個用來描述 UI 信息的 JavaScript 對象變成 DOM 元素,而且渲染到頁面上。

相關文章
相關標籤/搜索