iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0
自我挑戰組

程式碼 AI 寫,我負責看懂:30 天拆解 React × TypeScript系列 第 9

Day 09|v-if 去哪了?React 的條件渲染原來就是 JavaScript

  • 分享至 

  • xImage
  •  

今天換成來看看 Vue 的 v-ifReact 的條件渲染

假設今天在 Vue 專案中,如果要決定是否顯示某段內容時,我們可以使用 v-if這個方法

<!-- App.vue -->
<p v-if="todos.length > 0" class="summary">
  已完成 {{ completedCount }} / {{ todos.length }} 項
</p>

todos.length > 0 成立時,才會顯示完成進度;如果目前沒有任何待辦事項,這段內容就不會出現在畫面上。

而看到另一邊使用 React 的專案,跟 v-for 一樣,也找不到 v-if,但是會看到:

// App.tsx
{todos.length > 0 && (
  <p className="summary">
    已完成 {completedCount} / {todos.length} 項
  </p>
)}

這邊能看到 && 出現在 JSX 裡,雖然一開始看到不知道這個符號代表什麼意思,但我想應該多少也能猜到它的作用。
React 沒有另外提供 v-if 這類條件指令,而是直接使用 JavaScript 的條件判斷來決定要顯示哪些 JSX。

常見的寫法包括:

使用 if 回傳不同的 JSX

目前專案中的 TodoList.tsx 就使用了 JavaScript 的 if

function TodoList({ todos, onToggle, onDelete }: TodoListProps) {
  if (todos.length === 0) {
    return <p className="empty">目前沒有待辦事項,新增一筆看看吧!</p>
  }

  return (
    <ul className="todo-list">
      {todos.map((todo) => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={onToggle}
          onDelete={onDelete}
        />
      ))}
    </ul>
  )
}

當:

todos.length === 0

結果是 true 時,Component 會先回傳:

<p className="empty">
  目前沒有待辦事項,新增一筆看看吧!
</p>

程式執行到 return 後就會結束,因此後面的 Todo 清單不會被回傳。
如果 todos.length === 0 不成立,程式就會繼續往下執行並回傳 <ul>

這段程式碼可以理解成:

沒有待辦事項 → 顯示提示文字
有待辦事項 → 顯示 Todo 清單

React 的條件渲染並沒有什麼特別的魔法,就只是使用平常的 JavaScript if 決定要回傳哪一段 JSX。

使用 null 代表不顯示內容

有時候 Component 在某個條件下不需要顯示任何內容,這時可以回傳 null。
例如:

function TodoMessage({ todos }) {
  if (todos.length > 0) {
    return null
  }

  return <p>目前沒有待辦事項</p>
}

todos.length > 0 成立時,Component 會回傳:

null

React 收到 null 後,不會在畫面上顯示任何內容。
如果條件不成立,則會繼續往下執行並回傳:

<p>目前沒有待辦事項</p>

所以回傳 null

Component 仍然有回傳結果,只是這個結果不會產生任何畫面內容。

使用 && 決定是否顯示 JSX

如果只想在條件成立時顯示內容,否則什麼都不顯示,就可以使用 &&
目前 App.tsx 中的完成進度就是這樣處理:

{todos.length > 0 && (
  <p className="summary">
    已完成 {completedCount} / {todos.length} 項
  </p>
)}

可以把它拆成左右兩邊:
條件 && 要顯示的 JSX
左邊是條件:

todos.length > 0

右邊是條件成立時要顯示的 JSX:

<p className="summary">
  已完成 {completedCount} / {todos.length} 項
</p>

因此這整段可以這麼理解:

如果 todos.length > 0 成立,就顯示完成進度;否則什麼都不顯示。

這裡特別寫成:

todos.length > 0

而不是:

todos.length

是因為當 todos.length0 時,React 可能會將數字 0 顯示在畫面上。先使用 > 0 將結果轉成明確的 truefalse,就能避免這個問題。而這應該也算是常見的條件渲染方法。

使用三元運算子選擇其中一個結果

如果條件成立與不成立時,都各自有要使用的內容,就可以使用三元運算子:

條件 ? 成立時的結果 : 不成立時的結果

目前 TodoItem.tsx 會根據 Todo 是否完成,決定要使用哪一組 CSS class:

<span className={todo.completed ? 'text completed' : 'text'}>
  {todo.text}
</span>

這段程式碼的條件是:

todo.completed

todo.completedtrue 時,使用:

'text completed'

當它是 false 時,則使用:

'text'

所以同樣的,這整段可以理解成:

Todo 已完成 → className="text completed"
Todo 尚未完成 → className="text"

雖然這裡不是選擇要顯示哪一個 Component,而是選擇要使用哪個 className,背後使用的仍然是相同的 JavaScript 條件判斷。使用上整體給人一種更加簡潔的感覺,我自己也覺得熟悉這方法後反而還蠻直觀的。

if、null、&& 和三元運算子怎麼選?

目前可以先根據需求簡單區分:

1.使用 if

適合根據條件提早回傳不同的 JSX:

if (todos.length === 0) {
  return <p>目前沒有待辦事項</p>
}

return <TodoList />

2.使用 null

適合讓整個 Component 在特定條件下不顯示任何內容:

if (todos.length > 0) {
  return null
}

return <p>目前沒有待辦事項</p>

3.使用 &&

適合條件成立時顯示內容,否則什麼都不顯示:

{todos.length > 0 && <p>目前有待辦事項</p>}

4.使用三元運算子

適合條件成立與不成立時,各自使用不同的結果:

{todos.length > 0 ? <TodoList /> : <p>目前沒有待辦事項</p>}

不一定要為了讓程式碼看起來比較厲害,就把所有條件都塞進三元運算子裡。只要選擇當下比較容易閱讀的寫法就可以了。

Vue 的 v-if 和 React 條件渲染

將兩個專案放在一起比較:

<!-- Vue -->
<p v-if="todos.length > 0">
  已完成 {{ completedCount }} / {{ todos.length }} 項
</p>
// React
{todos.length > 0 && (
  <p>
    已完成 {completedCount} / {todos.length} 項
  </p>
)}

兩者都能根據條件決定是否顯示內容,主要差別在於:

  • Vue 使用 Template 指令 v-if
  • React 直接使用 JavaScript 條件判斷

React 不是沒有條件渲染,只是沒有另外設計一套 v-if 這類語法而已。

今日回顧

  • React 沒有 v-if 指令,而是使用 JavaScript 處理條件渲染
  • if 可以根據條件讓 Component 回傳不同的 JSX
  • Component 可以回傳 null,表示不顯示任何內容
  • && 適合在條件成立時顯示內容
  • 三元運算子適合在兩個結果之間選擇
  • 使用 && 時,左邊最好是明確的布林條件
  • 條件寫法不需要刻意複雜,選擇容易理解的方式就可以了

Vue 的 v-if 和 React 的條件渲染雖然寫法不同,但其實都是在處理同一件事:決定畫面上要出現什麼內容。
只是 React 就像是又再次把問題丟回來說:這個 JavaScript 本來就做得到R

那今天這篇就先到這邊~下篇見!


上一篇
Day 08|v-for 不見了:React 為什麼一直在 map()?
下一篇
Day 10|ref() 變成 useState()?兩個真的可以直接畫等號嗎?
系列文
程式碼 AI 寫,我負責看懂:30 天拆解 React × TypeScript22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言