今天換成來看看 Vue 的 v-if 跟 React 的條件渲染。
假設今天在 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
null
&&
? :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。
有時候 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.length 為 0 時,React 可能會將數字 0 顯示在畫面上。先使用 > 0 將結果轉成明確的 true 或 false,就能避免這個問題。而這應該也算是常見的條件渲染方法。
如果條件成立與不成立時,都各自有要使用的內容,就可以使用三元運算子:
條件 ? 成立時的結果 : 不成立時的結果
目前 TodoItem.tsx 會根據 Todo 是否完成,決定要使用哪一組 CSS class:
<span className={todo.completed ? 'text completed' : 'text'}>
{todo.text}
</span>
這段程式碼的條件是:
todo.completed
當 todo.completed 是 true 時,使用:
'text completed'
當它是 false 時,則使用:
'text'
所以同樣的,這整段可以理解成:
Todo 已完成 → className="text completed"
Todo 尚未完成 → className="text"
雖然這裡不是選擇要顯示哪一個 Component,而是選擇要使用哪個 className,背後使用的仍然是相同的 JavaScript 條件判斷。使用上整體給人一種更加簡潔的感覺,我自己也覺得熟悉這方法後反而還蠻直觀的。
目前可以先根據需求簡單區分:
if適合根據條件提早回傳不同的 JSX:
if (todos.length === 0) {
return <p>目前沒有待辦事項</p>
}
return <TodoList />
適合讓整個 Component 在特定條件下不顯示任何內容:
if (todos.length > 0) {
return null
}
return <p>目前沒有待辦事項</p>
適合條件成立時顯示內容,否則什麼都不顯示:
{todos.length > 0 && <p>目前有待辦事項</p>}
適合條件成立與不成立時,各自使用不同的結果:
{todos.length > 0 ? <TodoList /> : <p>目前沒有待辦事項</p>}
不一定要為了讓程式碼看起來比較厲害,就把所有條件都塞進三元運算子裡。只要選擇當下比較容易閱讀的寫法就可以了。
將兩個專案放在一起比較:
<!-- Vue -->
<p v-if="todos.length > 0">
已完成 {{ completedCount }} / {{ todos.length }} 項
</p>
// React
{todos.length > 0 && (
<p>
已完成 {completedCount} / {todos.length} 項
</p>
)}
兩者都能根據條件決定是否顯示內容,主要差別在於:
v-if
React 不是沒有條件渲染,只是沒有另外設計一套 v-if 這類語法而已。
v-if 指令,而是使用 JavaScript 處理條件渲染if 可以根據條件讓 Component 回傳不同的 JSX&& 適合在條件成立時顯示內容&& 時,左邊最好是明確的布林條件Vue 的 v-if 和 React 的條件渲染雖然寫法不同,但其實都是在處理同一件事:決定畫面上要出現什麼內容。
只是 React 就像是又再次把問題丟回來說:這個 JavaScript 本來就做得到R
那今天這篇就先到這邊~下篇見!