iT邦幫忙

2022 iThome 鐵人賽

DAY 18
0
Modern Web

終究都要學 React 何不現在學呢?系列 第 18

終究都要學 React 何不現在學呢? - React 進階 - Fragments - (18)

  • 分享至 

  • xImage
  •  

前言

Fragments 是一個實戰上非常常使用的技巧,它可以讓我們在寫 React 的時候,可以不用一定要包一層 div,這樣就可以讓我們的 HTML 結構更加乾淨,那麼該怎麼使用呢?讓我們一起來看看吧!

為什麼要使用 Fragments

在說明為什麼要使用 Fragments 之前,我們先來看看一個簡單的範例:

const App = () => {
  return (
    <div>
      <h1>Fragments Sample</h1>
      <h1>Fragments Sample</h1>
    </div>
  )
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

CodePen 連結

上面是一個很簡單的範例,我們以往開發都會用一個 <div> 包著內層,因為如果你外層不額外包一層的話,就會發生錯誤,什麼錯誤呢?讓我們來看看

const App = () => {
  return (
    <h1>Fragments Sample</h1>
    <h1>Fragments Sample</h1>
  )
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

CodePen 連結

基本上你是可以看到 CodePen 直接跳出一個提示訊息

Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

那麼為了解決這個問題,我們可能就會如同一開始範例那樣子使用一個 <div> 包著內層,但是這樣子的話,我們的 HTML 結構就會莫名多一個沒意義的 <div>,當專案越來越龐大時,這個沒有意義的 <div> 就會讓我們的 HTML 結構變得非常雜亂,因此 React 就提供了一個神兵利器 Fragments,讓我們可以不用一定要包一層 <div>,這樣就可以讓我們的 HTML 結構更加乾淨

const App = () => {
  return (
    <React.Fragment>
      <h1>Fragments Sample</h1>
      <h1>Fragments Sample</h1>
    </React.Fragment>
  )
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

CodePen 連結

當你使用 React.Fragment 之後你也可以發現原本的錯誤訊息就不見了,而且你的 HTML 結構也變得乾淨許多,這邊我們也可以來觀看 HTML 的結構是不是真的少了莫名其妙的 <div>

https://ithelp.ithome.com.tw/upload/images/20220928/20119486uthc2jB0jg.png

https://ithelp.ithome.com.tw/upload/images/20220928/2011948681NuGz8hqU.png

相信兩者比較下來,你應該會比較喜歡 React.Fragment

那麼 React.Fragment 其實還有簡寫的方式,就是使用 <>,這樣子你寫起來可以更愉快

const App = () => {
  return (
    <>
      <h1>Fragments Sample</h1>
      <h1>Fragments Sample</h1>
    </>
  )
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

CodePen 連結

那麼有沒有發現 React.Fragment 與 Vue 的 <template> 有點像呢?Vue 的 <template> 也是用來包裝多個元素,但是不會在 HTML 結構中產生多餘的元素,讓我們回顧一下 Vue 的 <template> 是如何使用的

<div id="app">
  <template v-if="true">
    <h1>Template Sample</h1>
    <h1>Template Sample</h1>
  </template>
</div>
const { createApp } = Vue;

const app = createApp({
  setup() {
  }
});

app.mount('#app');

CodePen 連結

我們可以看到 Vue 的 <template> 也是不會在 HTML 結構中產生多餘的元素

https://ithelp.ithome.com.tw/upload/images/20220928/20119486GIrJm2Zosg.png

前面有提到 <></>React.Fragment 的簡寫,而它也有自己的名稱也就是 Empty Tag,這個名稱是因為它是一個空標籤。

Empty 與 Fragment 的差異

<></>React.Fragment 有什麼差異呢?一般狀況下兩者是沒有什麼太大差異的

const App = () => {
  return (
    <>
      <h1>Empty Sample</h1>
      <h1>Empty Sample</h1>
    </>
  )
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

CodePen 連結

const App = () => {
  return (
    <React.Fragment>
      <h1>Empty Sample</h1>
      <h1>Empty Sample</h1>
    </React.Fragment>
  )
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

CodePen 連結

但我們通常在跑一段迴圈時,通常 React 會提示你要補上 key,而這時候你就不可以使用 Empty tag,因為 Empty tag 是沒有 keyattribute (屬性) 的,所以你必須使用 React.Fragment 來包著,並將 key 寫在 React.Fragment

const App = () => {
  const list = [1, 2, 3, 4, 5];
  return (
    <>
      {list.map((item, index) => (
        <React.Fragment key={index}>
          <h1 key={index}>{item}</h1>
        </React.Fragment>
      ))}
    </>
  )
}


const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

CodePen 連結

所以這邊我才沒有特別說明 Empty tag 是 React.Fragment 的語法糖,因為它們在使用上有一些差異。

後記

本文將會同步更新到我的部落格


上一篇
終究都要學 React 何不現在學呢? - React 進階 - Custom Hook - (17)
下一篇
終究都要學 React 何不現在學呢? - React CRA - CRA 建立 - (19)
系列文
終究都要學 React 何不現在學呢?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言