iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0

了解完畫面渲染以及元件的生命週期後,接著來看看可以被Vue和React轉換成Virtual DOM的HTML的部分要怎麼寫吧!這個部分雖然沒有很困難,但老實說從Vue轉換到React我在一開始的時候,還是稍微有點不習慣,因為用v-for和v-if真的用得太習慣了。那究竟差異在哪呢?就直接給他看下去吧!

Template 是什麼?

<template>
  <div class="greetings">
    <h1 class="green">{{ msg }}</h1>
    <h3>
      You’ve successfully created a project with
      <a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a>
    </h3>
  </div>
</template>

「Template」是Vue官方推薦來定義元件顯示結構的HTML模板語法,原本就寫Vue的朋友應該都對Vue的Template很熟悉。使用它的時候,可以用大家都很熟悉的HTML寫法搭配template語法達到一些特定條件的畫面呈現方式。雖然看起來是很單純的在寫HTML,不過實際上寫出來的內容卻會被轉換成Vue的渲染函式。

看起來是寫HTML

<template>
  <h1 className="greeting">
    Hi! I am <i>{{name}}</i>
  </h1>
</template>

實際上會被轉換成渲染函式

render() {
  return this.$createElement('h1', { class: 'greeting' }, [
    'Hi! I am ',
    this.$createElement('i', this.name)
  ]);
}

雖然剛開始接觸Template的時候,需要了解特定用法中,它的語法該怎麼寫,但是當我們熟悉了寫法後,想要透過迴圈的方式寫,或是透過一些state來決定某一段HTML要不要顯示或是該怎麼顯示時,Template所提供的寫法都是讓我們更快達到這個目的的好幫手。

補充一下:如果想要在Vue中使用JSX也可以,但官方是推薦使用vue專屬的Template。

JSX是什麼?

import { useState } from 'react';

export default function Content() {
  const [count, setNumber] = useState(1);
  const handleAddCount = () => {
    setNumber(count + 1);
  };
  return (
    <div>
      <p>current count: {count}</p>
      <button onClick={handleAddCount}>add</button>
    </div>
  )
}

JSX和Template一樣是在定義元件顯示的內容,雖然在定義HTML結構的時候,可以像在寫一般HTML一樣,去寫要用哪些HTML標籤,但這其實是JSX提供的語法糖,實際上你還是在寫JavaScript,而那個語法糖最後也會將你像在寫一般HTML的內容轉換成使用React.createElement()的寫法。

看起來是在寫HTML

function Greeting({name}) {
  return (
    <h1 className="greeting">
      Hi! I am <i>{name}</i>
    </h1>
  );
}

實際上JSX會把看起來是在寫HTML的內容轉換成React.createElement()的寫法。


function Greeting() {
  return React.createElement(
    'h1',
    { className: 'greeting' },
    'Hi! I am ',
    React.createElement('i', null, name)
  );
}

另外,與Template不同的是因為JSX就是在寫JavaScript,所以並沒有一些需要額外去記的寫法,例如想要用Template用法中的v-if、v-for的效果,可以很單純地透過大家最熟悉的JavaScript的寫法去呈現。還有一個需要特別注意的是因為寫JSX就是在寫JavaScript,所以在寫HTML的class的時候,會需要改寫成className,Javascript才不會把它誤認是它自己本身就有的class。

接下來也來透過一些Vue Template中常用的寫法來看看用JSX要怎麼寫!

Template vs. JSX 的寫法差異

可以接受的根元素數量不同

從Vue3開始Template就可以接受多個根元素,所以不用再跟以前一樣一定要包一層沒有任何用途的div在最外層,可以直接寫自己希望的HTML結構。

<template>
  <input type="text" >
  <button>Click</button>
</template>

寫JSX的時候,則不接受多個根元素,因為React.createElement只會回傳一個React element,所以如果寫多個根元素的話,就無法成功轉換成React.createElement()的寫法。
因為這個緣故,在實際撰寫的時候,也就需要在外層多包一層HTML元素。但是如果是用div包在最外層的話,會讓最後的HTML多了一個層沒有必要的div,想避免這種情況的時候,就可以使用Fragement或空的標<>來包在最外層。

所以可以寫成這樣

export default function RefCom() {
  return (
    <Fragement>
      <h1>title</h1>
      <p>description</p>
    </Fragement>
  )
}

也可以寫成這樣

export default function RefCom() {
  return (
    <>
      <h1>title</h1>
      <p>description</p>
    </>
  )
}

嚴格的使用閉合標籤

在Template中,不需要嚴格的使用閉合標籤,template會自動幫忙處理這個部分,所以可以這樣寫在template裡面。

<template>
  <input type="text">
  <img src="a.jpg" alt="a" >
</template>

但是寫jsx的時候,就必需要嚴格的使用閉合標籤,這樣jsx才能正常解析這個內容。

<input type="text" />
<img src="a.jpg" alt="a" />

依照條件渲染該怎麼寫?

如果是寫Template的話,我們需要使用v-if和v-else這樣的語法下去讓畫面可以依照state下去切換成正確該顯示成什麼。

<template>
  <div>
    <p class="special" v-if="isSpecialMode">special mode</p>
    <p v-else>normal mode</p>
    <button @click="handleModeToggle">toggle</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const isSpecialMode = ref(false);
const handleModeToggle = () => {
  isSpecialMode.value = !isSpecialMode.value
};
</script>

如果是寫JSX的話,就需要記得現在自己是在寫JavaScript,所以需要用寫JavaSctipy的思考模式下去呈現,所以可以寫if else、三元運算,也可以用switch、&&或||的寫法來呈現。

import './App.css';
import { useState } from 'react';

function App() {
  const [isSpecialMode, setIsSpecialMode] = useState(false);
  const handleToggleMode = () => {
    setIsSpecialMode(!isSpecialMode);
  };
  return (
    <div className="App">
      {
        isSpecialMode ? <p className="special">special mode</p> : <p>normal mode</p>
      }
      <button onClick={handleToggleMode}>Toggle</button>
    </div>
  );
}

export default App;

跑迴圈渲染又該怎麼寫?

如果是寫Template,我們可以使用v-for這個語法下去讓畫面用跑迴圈的方式呈現,以減少重複結構的程式碼出現,重複出現的部分就可以只寫一次。

<template>
  <ul>
    <li v-for="listItem in list" :key="listItem.id">{{ listItem.name }}</li>
  </ul>
</template>

<script setup>
import { ref } from 'vue';
const list = ref([
  {
    id: 1,
    name: 'apple',
  },
  {
    id: 2,
    name: 'lemon',
  },
  {
    id: 3,
    name: 'orange',
  }
]);
</script>

寫JSX的話,一樣也是要轉換成在寫JavaScript的大腦,用JavaScript跑迴圈方式下去寫就可以,主要都是以map的寫法下去寫。

function App() {
  const list = [
    {
      id: 1,
      name: 'apple',
    },
    {
      id: 2,
      name: 'lemon',
    },
    {
      id: 3,
      name: 'orange',
    }
  ];
  return (
    <div className="App">
      <ul>
        {
          list.map((item) => (
            <li key={item.id}>{ item.name }</li>
          ))
        }
      </ul>
    </div>
  );
}

export default App;

事件、變數綁定及帶變數到畫面上

如果要把事件或變數綁定在Template上,需要使用v-on及v-bind的寫法,大多時候都會簡寫為@和:。如果是想要把變數帶到畫面上顯示,則是透過{{}}。

<template>
  <div>
    <!-- 放上變數 -->
    <p>{{ count }}</p>
    <!-- 綁定事件 -->
    <button @click="handleAdd">Add</button>
    <!-- 綁定變數 -->
    <ChildComponent :msg="msg" />
  </div>
</template>

在這個部分寫JSX的寫法也有差異,只要使用JSX的以on開頭的事件名稱即可,綁定變數也只要用以下這樣的寫法就可以。

import './App.css';
import { useState } from 'react';
import ChildComponent from './components/ChildComponent';

function App() {
  const [count, setCount] = useState(0);
  const handleCountAdd = () => {
    setCount(count + 1);
  };
  return (
    <div className="App">
      // 放上變數
      <p>count: {count}</p>
      // 綁定事件
      <button onClick={handleCountAdd}>Toggle</button>
      // 綁定變數
      <ChildComponent count={count} />
    </div>
  );
}

export default App;

總結

今天快速看了一下Vue及React在HTML部分的寫法,雖然Template和JSX看起來都像在寫單純的HTML,但實際上都不是在寫HTML,一個是Vue提供的模板語法,一個則是在寫JavaScript,也是因為它們實際上都不是HTML,所以才可以搭配Vue及React的渲染機制產生Virtual DOM,而最終都將被轉換成Virtual DOM物件。如果原本是習慣Vue的Template寫法的人,只要記得JSX其實是在寫JavaScript,並以寫JavaScript的方向下去思考,就會比較快熟悉JSX的寫法。

那Template和JSX的部分就看這裡,明天先休息一下,暫時忘掉React和Vue,來看一下不管寫React還是寫Vue都很重要的一個資料流的design pattern - 單向資料流。

參考資料

createElement
Writing Markup with JSX


上一篇
【Day 6】元件的一生!Vue的生命週期 vs. React的生命週期
下一篇
【Day 8】一個與Vue和React有密切關係的概念-單向資料流
系列文
從Vue學React!不只要會用,還要真的懂~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言