條件式渲染

你的元件通常需要根據不同的條件顯示不同的內容。在 React 中,你可以使用 JavaScript 語法(例如 if 陳述式、&&? : 運算子)來條件式渲染 JSX。

你將會學到

  • 如何根據條件返回不同的 JSX
  • 如何有條件地包含或排除一段 JSX
  • 在 React 程式碼庫中常見的條件語法捷徑

條件式返回 JSX

假設你有一個 PackingList 元件渲染多個 Item,這些項目可以標記為已打包或未打包

function Item({ name, isPacked }) {
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

請注意,某些 Item 元件的 isPacked prop 設定為 true 而不是 false。如果 isPacked={true},你想要在已打包的項目上新增一個核取記號 (✅)。

你可以將它寫成 if/else 陳述式,如下所示

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

如果 isPacked prop 為 true,則此程式碼會**返回不同的 JSX 樹狀結構。** 經過此更改後,某些項目末尾會出現核取記號

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name}</li>;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

試著編輯在任一情況下返回的內容,看看結果如何變化!

請注意,你如何使用 JavaScript 的 ifreturn 陳述式來建立分支邏輯。在 React 中,控制流程(例如條件)是由 JavaScript 處理的。

使用 null 有條件地不返回任何內容

在某些情況下,你根本不想渲染任何內容。例如,假設你根本不想顯示已打包的項目。元件必須返回某些內容。在這種情況下,你可以返回 null

if (isPacked) {
return null;
}
return <li className="item">{name}</li>;

如果 isPacked 為 true,則元件將不返回任何內容,null。否則,它將返回要渲染的 JSX。

function Item({ name, isPacked }) {
  if (isPacked) {
    return null;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

實際上,從元件返回 null 並不常見,因為這可能會讓嘗試渲染它的開發人員感到驚訝。更常見的情況是,你會在父元件的 JSX 中有條件地包含或排除該元件。以下是執行此操作的方法!

條件式包含 JSX

在前面的範例中,你控制了元件將返回哪個(如果有的話!)JSX 樹狀結構。你可能已經注意到渲染輸出中的一些重複

<li className="item">{name}</li>

非常類似於

<li className="item">{name}</li>

兩個條件分支都會返回 <li className="item">...</li>

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

雖然這種重複無害,但它可能會使你的程式碼更難維護。如果你想更改 className 呢?你必須在程式碼中的兩個地方進行更改!在這種情況下,你可以有條件地包含一些 JSX 來使你的程式碼更 DRY(不要重複自己)。

條件(三元)運算符 (? :)

JavaScript 有一個用於編寫條件表達式的簡潔語法 — 稱為 條件運算符 或「三元運算符」。

取代以下寫法

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

你可以這樣寫

return (
<li className="item">
{isPacked ? name + ' ✅' : name}
</li>
);

你可以將其理解為 *「如果 isPacked 為 true,則(?)渲染 name + ' ✅',否則(:)渲染 name」*。

深入探討

這兩個例子完全相等嗎?

如果你有物件導向程式設計的背景,你可能會認為上述兩個例子略有不同,因為其中一個例子可能會建立兩個不同的 <li>「實例」。但 JSX 元素不是「實例」,因為它們不持有任何內部狀態,也不是真正的 DOM 節點。它們是輕量級的描述,就像藍圖一樣。所以這兩個例子實際上是*完全相等的*。保存和重置狀態 詳細說明了這是如何運作的。

現在假設你想將已完成項目的文字包裝到另一個 HTML 標籤中,例如 <del> 來將其刪除線。你可以新增更多換行符和括號,以便更容易在每種情況下巢狀更多 JSX

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {isPacked ? (
        <del>
          {name + ' ✅'}
        </del>
      ) : (
        name
      )}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

這種樣式適用於簡單的條件,但請適量使用。如果你的元件因為過多巢狀的條件標記而變得混亂,請考慮提取子元件來清理程式碼。在 React 中,標記是你程式碼的一部分,因此你可以使用變數和函數等工具來整理複雜的表達式。

邏輯 AND 運算符 (&&)

你會遇到的另一個常見捷徑是 JavaScript 邏輯 AND (&&) 運算符。 在 React 元件中,當你想在條件為 true 時渲染一些 JSX,**否則不渲染任何東西時**,它經常出現。使用 &&,你可以有條件地僅在 isPackedtrue 時才渲染核取記號

return (
<li className="item">
{name} {isPacked && '✅'}
</li>
);

你可以將其理解為 *「如果 isPacked,則(&&) 渲染核取記號,否則,不渲染任何東西」*。

實際應用如下

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✅'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

JavaScript && 表達式 如果左側(我們的條件)為 true,則返回其右側的值(在我們的例子中為核取記號)。但如果條件為 false,則整個表達式變為 false。React 將 false 視為 JSX 樹中的「空洞」,就像 nullundefined 一樣,並且不會在其位置渲染任何東西。

陷阱

不要將數字放在 && 的左側。

為了測試條件,JavaScript 會自動將左側轉換為布林值。但是,如果左側是 0,則整個表達式將獲得該值 (0),React 將會渲染 0 而不是什麼都不渲染。

例如,一個常見的錯誤是編寫像 messageCount && <p>新訊息</p> 這樣的程式碼。很容易假設當 messageCount0 時它不會渲染任何東西,但它實際上渲染了 0 本身!

要修復它,請使左側成為布林值:messageCount > 0 && <p>新訊息</p>

有條件地將 JSX 分配給變數

當捷徑妨礙編寫簡潔的程式碼時,請嘗試使用 if 陳述式和變數。你可以重新分配使用 let 定義的變數,因此首先提供你要顯示的預設內容,即名稱

let itemContent = name;

如果 isPackedtrue,請使用 if 陳述式將 JSX 表達式重新分配給 itemContent

if (isPacked) {
itemContent = name + " ✅";
}

大括號開啟了「通往 JavaScript 的視窗」。 在返回的 JSX 樹中使用大括號嵌入變數,將先前計算的表達式嵌套在 JSX 內部

<li className="item">
{itemContent}
</li>

這種風格最冗長,但也最靈活。以下是實際應用

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✅";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

和之前一樣,這不僅適用於文字,也適用於任意 JSX

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = (
      <del>
        {name + " ✅"}
      </del>
    );
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

如果您不熟悉 JavaScript,一開始可能會覺得這些樣式令人不知所措。但是,學習它們將幫助您讀寫任何 JavaScript 程式碼,而不僅僅是 React 元件!首先選擇您喜歡的樣式,如果您忘記其他樣式如何運作,請再次參考此處。

重點回顧

  • 在 React 中,您可以使用 JavaScript 控制分支邏輯。
  • 您可以使用 if 陳述式有條件地返回 JSX 表達式。
  • 您可以有條件地將一些 JSX 儲存到變數中,然後使用大括號將其包含在其他 JSX 中。
  • 在 JSX 中,{cond ? <A /> : <B />} 表示 *「如果 cond,則渲染 <A />,否則渲染 <B />」*。
  • 在 JSX 中,{cond && <A />} 表示 *「如果 cond,則渲染 <A />,否則不渲染任何內容」*。
  • 這些捷徑很常見,但如果您喜歡普通的 if,則不必使用它們。

挑戰 1 3:
使用 ? : 顯示未完成項目的圖示

如果 isPacked 不是 true,請使用條件運算子(cond ? a : b)來渲染 ❌。

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✅'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}