iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 1
2
Modern Web

React + GraphQL 全端練習筆記系列 第 1

React 基礎簡介 - React element與JSX

本系列文以製作專案為主軸,紀錄小弟學習React以及GrahQL的過程。主要是記下重點步驟以及我覺得需要記憶的部分,有覺得不明確的地方還請留言多多指教。

在進行專案前筆記一些React的基礎觀念,在專案進行中穿插這些觀念感覺太破碎,先整理起來。

React 用 component 的方式讓頁面能夠拆分成許多部件,方便去思考各個部件要:

  1. View 顯示什麼
  2. Model 傳遞什麼資料
  3. Contorl 根據什麼邏輯做什麼反應(點擊、輸入...etc)

延續學習Vue的時候對Component的理解,在學習React的時候也是從MVC三點入手,接下來就按順序討論,先談 View。

React Element

React切版的基礎單元是 React element,這東西來自:

React.createElement(
  type,
  [props],
  [...children]
)

簡單範例:

React.createElement("div", null, "Hello world!");

上面的程式編譯成html會變成:

<div>Hello world!</div>

這個function的詳細介紹就跳過了,因為平常根本不會用到,只是他是JSX的基礎,知道有這個function後再來介紹JSX比較有頭緒,大概了解一下就好。

JSX

React 建構UI的方式就是將一個個element堆疊起來,但一直寫React.createElement實在太繁瑣了,像是要產生

<div>
    <p>Hello world!</p>    
</div>

用React.createElement的話:

React.createElement(
    "div", 
    null, 
    React.createElement(
        "p",
        null,
        "Hello world!"));

每多一層就要多掛一個React.createElement在children的位子上,
雖然能用變數(例: const Hello = React.createElement(...))取代,但還是繁瑣,這也是JSX登場的時候了。

先來個簡單的JSX範例:

const element = <div>Hello, world</div>

嗯? 這是 html?但是有 expression,所以是 javascript?

初次看到 JSX 的時候用之前學樣板語言的方式去理解總覺得哪裡怪怪的,後來在閱讀文件後覺得要理解 JSX ,首先要認識的就是, JSX 跟一般樣板語言最不同的部分在於編譯後首先產生的是 Object ,不是 html。

JSX 經由 Babel 編譯後首先會轉成 React.createElement 的 Object ,而既然是 Object ,就能像上面的範例一樣,參照給 expression,也能用陣列存起一串 JSX ,像是:

const list = [
    <li>1</li>,
    <li>2</li>, 
    <li>3</li>
    ];    

或者用條件式判斷要回傳不同的JSX

if(show === true){
    return <h1>YES</h1>
}
else{
    return <h1>NO</h1>
}

而巢狀的 JSX ,也是由 children 的部分先轉成 object,傳給 createElement 後產出上層的 object

JSX:

const element = (
  <div>
    <h1 name="title">Hello world!</h1>
  </div>
)

編譯後

 const element = React.createElement(
                 "div", 
                 null, 
                 React.createElement(
                     "h1", 
                     {name: "title"}, 
                      "Hello world!"));

所以之前提到的繁瑣工作就由Babel代勞了,因為 JSX 近似於 html 格式,也不需要再煩惱層狀構造怎麼進行轉換的問題。

關於 JSX 怎麼轉換成 createElement 的可以到Babel的線上編譯器進行嘗試。

理解 JSX 能夠作為 object 在 javascript 中運用後,來看看怎麼在 JSX 當中運用 javascript。

用大括號將 expression 帶入 JSX:

const element = <img src={user.avatarUrl}></img>;

大括號裡可以帶入任何 javascript expression,像是 arr[0] , {id:"1",name:"user1"} (會有兩層大括號),arrow function 也可以。

Inline if 條件判斷範例:

<div>
  <h1>Hello!</h1>
  {unreadMessages.length > 0 &&
    <h2>
      You have {unreadMessages.length} unread messages.
    </h2>
  }
</div>

格式像這樣

{ [條件判斷式] && 
    [判斷為true時回傳的JSX]
}

Inline if-else條件判斷範例:

<div>
  The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>

格式像這樣

{ [條件判斷式] ? [true時回傳的JSX]:[false時回傳的JSX]}

用陣列產生list:

function NumberList() {
    const numbers = [1, 2, 3, 4, 5];
    return (
      <ul>
        {numbers.map((number) => (
          <li key={number.toString()}>{number}</li>
        ))}
      </ul>
    );
}

利用javascript 的 Array.map() 函式將陣列轉換成JSX陣列,當成其他樣板語言裡的 for loop 理解就行。

要注意的重點在 key ,必須指定獨特的 key 給每個 sibling,不然 React 在比對 virtual dom 的時候會無法分辨 element 間的差別。關於 virtual dom 容後再談,先了解 key必須是獨特值,一般會用資料的 id,再不然也要用陣列index,不過index會有其他問題,這也是之後再談。

不過key的獨特性只要保持在同node下的siblings之間就好,不同node底下map清單的話key相同也無妨。

ReactDOM.render

談完 JSX 的使用後再回頭來了解下JSX最後是怎麼跟html掛鉤的。

看看上一篇用CRA建立的專案裡,index.js當中

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

ReactDOM.render可說是React框架的主輸出口,在所有component用JSX產出element一個個往上傳遞,最後集大成的element就會由ReactDOM.render渲染到指定的node底下,像是這邊的 document.getElementById("root")。

也可以呼叫多個ReactDOM.render在不同的root上渲染element,不過當ReactDOM.render第一次被呼叫的時候會清空目標底下所有node,再掛上自己渲染的node,所以如果多個render對一個root的話只會剩下最後一個。

References:


下一篇
React 基礎簡介 - React Component 與 Hooks
系列文
React + GraphQL 全端練習筆記30

尚未有邦友留言

立即登入留言