【譯】React條件渲染

原文連接:www.robinwieruch.de/conditional…
原做者:Robin Wieruchreact

在 React 中使用條件渲染並不困難。在 JSX 中——用於 React 的語法擴展——您可使用純 JavaScript,其中包括 if else 語句、三元操做符、 switch case 語句等等。在條件渲染中,React 組件根據一個或多個條件決定將返回哪些 DOM 元素。 例如,基於某種邏輯,它能夠返回一個項目列表或者一個文本,上面寫着「對不起,列表是空的」。當組件具備條件渲染時,渲染的組件外觀根據條件不一樣而不一樣。本文旨在爲 React 中的條件渲染和這些模式的最佳實踐提供一個詳盡的選擇清單。函數

目錄

  • React條件渲染:if
  • React條件渲染:if else
  • React條件渲染:三元
  • React條件渲染:&&
  • React條件渲染:switch case
  • React多條件渲染
  • React嵌套條件渲染
  • 使用HOC的條件渲染
  • React中的if else組件

React條件渲染:if

React 中最基本的條件渲染邏輯是用一個 if 語句完成的。假設您不想在 React 組件中渲染某些內容,由於它沒有必要的 React props 可用。 例如,若是開始沒有list的話,React 中的 List 組件不該該在視圖中渲染list的HTML元素。 你可使用一個簡單的 JavaScript if 語句提早返回(守衛模式) :學習

const users = [
  { id: '1', firstName: 'Robin', lastName: 'Wieruch' },
  { id: '2', firstName: 'Dennis', lastName: 'Wieruch' },
];
function App() {
  return (
    <div>
      <h1>Hello Conditional Rendering</h1>
      <List list={users} />
    </div>
  );
}
function List({ list }) {
  if (!list) {
    return null;
  }
  return (
    <ul>
      {list.map(item => (
        <Item key={item.id} item={item} />
      ))}
    </ul>
  );
}
function Item({ item }) {
  return (
    <li>
      {item.firstName} {item.lastName}
    </li>
  );
}
複製代碼

您能夠本身嘗試將用戶設置爲 null 或 undefined。 若是props中的信息爲 null 或 undefined,則 React 組件在條件渲染中返回 null。 在這裏,返回 null 而不是 JSX 的 React 組件將不渲染任何內容。ui

在這個例子中,咱們已經完成了基於 props 的條件渲染,可是條件渲染也能夠基於 state 和 hooks 。 注意,咱們尚未在 JSX 內部使用 if 語句,而只是在 return 語句以前在外部使用 if 語句。spa

React條件渲染:if else

讓咱們繼續前面的例子來學習 React 中的 if else 語句。 若是沒有list,咱們就不渲染任何內容,並隱藏 HTML,就像咱們以前用單個 if 語句所看到的那樣。 可是,爲了得到更好的用戶體驗,當list爲空時,您可能但願爲用戶顯示一個文本做爲反饋。 這將與另外一個 if 語句一塊兒使用,可是咱們將用 if else 語句擴展這個例子:code

function List({ list }) {
  if (!list) {
    return null;
  }
  if (!list.length) {
    return <p>Sorry, the list is empty.</p>;
  } else {
    return (
      <div> {list.map(item => ( <Item item={item} /> ))} </div> ); } } 複製代碼

如今,List 組件根據一些 JavaScript 邏輯不渲染任何內容、文本或列表。儘管前面的例子展現瞭如何在 React 中使用 if else 語句,我仍是建議在每次須要保護主返回內容時使用單個 if 語句(這裏: 返回列表)做爲最佳實踐:xml

function List({ list }) {
  if (!list) {
    return null;
  }
  if (!list.length) {
    return <p>Sorry, the list is empty.</p>;
  }
  return (
    <div> {list.map(item => ( <Item item={item} /> ))} </div> ); } 複製代碼

這比以前的 if else 條件渲染更具可讀性。 全部守衛整齊地排列爲主返回語句以前的 if 語句,這也能夠解釋爲隱含的 else 語句。 儘管如此,在 return 語句中尚未使用 if 和 else 語句。對象

React條件渲染:三元

的確,咱們能夠在 JSX 中使用 JavaScript,可是在 JSX 中使用 if,else,switch case 這樣的語句會變得很困難。 沒有真正的方法來內聯它。 在 JavaScript 中表達 if else 語句的另外一種方式是三元運算符:教程

// if else
function getFood(isVegetarian) {
  if (isVegetarian) {
    return 'tofu';
  } else {
    return 'fish';
  }
}
// ternary operator
function getFood(isVegetarian) {
  return isVegetarian ? 'tofu' : 'fish';
}
複製代碼

例如,假設您的組件顯示預覽或編輯模式。 條件是一個 JavaScript 布爾值,以 React prop 的形式出現。 你可使用布爾值來決定你想要條件渲染哪一個元素:接口

function Recipe({ food, isEdit }) {
  return (
    <div>
      {food.name}
      {isEdit ? (
        <EditRecipe food={food} />
      ) : (
        <ShowRecipe food={food} />
      )}
    </div>
  );
}
複製代碼

三元操做符中兩個隱式 return 語句周圍的括號()使您可以返回單個或多個 HTML 元素,或從那裏返回 React 組件。 若是隻有一個元素,能夠省略括號。

注意: 有時候你須要用一個 div 元素包裹多行元素做爲一個塊。 無論怎樣,儘可能保持輕量化。 若是()之間包裹的內容太大,能夠考慮將其做爲組件提取,如示例中所示。

在 React 中使用三元運算渲染不只使條件渲染更加簡潔,並且爲你在返回中內嵌條件渲染提供了一種簡單的方法。 這樣,只有一部分 JSX 是有條件地渲染的,而其餘部分能夠不受任何條件限制地保持完整。

React條件渲染:&&

這種狀況常常發生,你想要渲染一個元素或者什麼都不渲染。 你已經知道一個簡單的if條件能夠幫助解決這個問題。 可是,您仍是但願可以像三元運算符那樣內聯條件。 使用下面的加載指示符組件,它使用條件三元操做符返回元素或者什麼都不返回:

function LoadingIndicator({ isLoading }) {
  return <div>{isLoading ? <p>Loading...</p> : null}</div>;
}
複製代碼

這個完成的不錯,你在你的 JSX 內聯了條件。 然而,還有一種替代方法能夠省略返回 null 的必要性。

邏輯 && 運算符能夠幫助您使返回 null 的條件更簡潔。 在 JavaScript 中,一個 true && Hello World 老是等於 Hello World。 False && Hello World 老是被計算爲 false:

const result = true && 'Hello World';
console.log(result);
// Hello World
const result = false && 'Hello World';
console.log(result);
// false
複製代碼

在React中,你能夠利用這種行爲。 若是條件爲真,邏輯 && 運算符後面的表達式將做爲輸出。 若是條件爲 false,React 忽略並跳過表達式:

function LoadingIndicator({ isLoading }) {
  return <div>{isLoading && <p>Loading...</p>}</div>;
}
複製代碼

當您但願不返回任何內容或 JSX 中的元素時,這是您的方式。 它也被稱爲短路求值,這使得它甚至比三元操做符更簡潔。

React條件渲染:switch case

如今可能會出現多個條件渲染的狀況。 例如,通知組件基於狀態字符串渲染錯誤、警告或信息組件:

function Notification({ text, status }) {
  if (status === 'info') {
    return <Info text={text} />;
  }
  if (status === 'warning') {
    return <Warning text={text} />;
  }
  if (status === 'error') {
    return <Error text={text} />;
  }
  return null;
}
複製代碼

您可使用 switch case 操做符來處理多個條件渲染:

function Notification({ text, status }) {
  switch (status) {
    case 'info':
      return <Info text={text} />;
    case 'warning':
      return <Warning text={text} />;
    case 'error':
      return <Error text={text} />;
    default:
      return null;
  }
}
複製代碼

對 switch case 操做符使用 default 是明智的,由於 React 組件老是必須返回一個元素或 null。 若是一個組件有一個基於字符串的條件渲染,那麼用 TypeScript 來描述組件的接口是有意義的:

type Status = 'info' | 'warning' | 'error';
type NotificationProps = {
  text: string;
  status: Status;
};
function Notification({ text, status }: NotificationProps) {
  switch (status) {
    case 'info':
      return <Info text={text} />;
    case 'warning':
      return <Warning text={text} />;
    case 'error':
      return <Error text={text} />;
    default:
      return null;
  }
}
複製代碼

對於多個條件渲染來講,switch case 寫是一個很好的開始。 可是它也有一樣的缺點,就像 if else 語句同樣。 不能在 JSX 中使用 switch case,對吧? 實際上它能夠經過一個條件渲染函數來實現,這個函數是自調用的:

function Notification({ text, status }) {
  return (
    <div>
      {(function() {
        switch (status) {
          case 'info':
            return <Info text={text} />;
          case 'warning':
            return <Warning text={text} />;
          case 'error':
            return <Error text={text} />;
          default:
            return null;
        }
      })()}
    </div>
  );
}
複製代碼

能夠選擇使用條件渲染箭頭函數使 switch case 更簡潔:

function Notification({ text, status }) {
  return (
    <div>
      {(() => {
        switch (status) {
          case 'info':
            return <Info text={text} />;
          case 'warning':
            return <Warning text={text} />;
          case 'error':
            return <Error text={text} />;
          default:
            return null;
        }
      })()}
    </div>
  );
}
複製代碼

總之,switch case 操做符能夠幫助您實現多個條件渲染。 可是這是最好的方法嗎? 讓咱們看看如何用枚舉來代替多個條件渲染。

React多條件渲染

帶有映射關係的鍵值對的 JavaScript 對象稱爲枚舉:

const NOTIFICATION_STATES = {
  info: 'Did you know? ...',
  warning: 'Be careful here ...',
  error: 'Something went wrong ...',
};
複製代碼

枚舉是處理 React 中帶有多個條件的條件渲染的一種很好的方法。 它們比 switch case 語句更給力,由於它們能夠在 JSX 中使用。 讓咱們再次考慮通知組件,但此次使用枚舉做爲內聯對象(內部花括號) :

function Notification({ text, status }) {
  return (
    <div>
      {
        {
          info: <Info text={text} />,
          warning: <Warning text={text} />,
          error: <Error text={text} />,
        }[status]
      }
    </div>
  );
}
複製代碼

status 屬性鍵幫助咱們從對象中檢索值。 很棒,不是嗎? 與 switch case 寫操做符相比,它更具可讀性。

在本例中,咱們必須使用內聯對象,由於對象的值依賴於 text 屬性。 不管如何,這是我推薦的方式。 可是,若是它不依賴於 text 屬性,你可使用一個枚舉做爲條件渲染的常量:

const NOTIFICATION_STATES = {
  info: <Info />, warning: <Warning />, error: <Error />, }; function Notification({ status }) { return ( <div> {NOTIFICATION_STATES[status]} </div> ); } 複製代碼

這樣事情就解決了。 若是咱們仍然依賴以前的 text 屬性,咱們可使用一個帶有函數的條件渲染來檢索值:

const getNotification = text => ({
  info: <Info text={text} />,
  warning: <Warning text={text} />,
  error: <Error text={text} />,
});
function Notification({ status, text }) {
  return <div>{getNotification(text)[status]}</div>;
}
複製代碼

畢竟,React 中的枚舉條件渲染比 switch case 語句更優雅。 做爲枚舉的對象提供了大量的選項來實現多個條件渲染。 布爾型的排列也是可能的:

function Message({ isExtrovert, isVegetarian }) {
  const key = `${isExtrovert}-${isVegetarian}`;
  return (
    <div> { { 'true-true': <p>I am an extroverted vegetarian.</p>, 'true-false': <p>I am an extroverted meat eater.</p>, 'false-true': <p>I am an introverted vegetarian.</p>, 'false-false': <p>I am an introverted meat eater.</p>, }[key] } </div>
  );
}
複製代碼

最後一個例子有點過頭了,我不建議使用它。 然而,當涉及到條件渲染,枚舉是我最喜歡的一個React模式。

React嵌套條件渲染

那麼在 React 中嵌套條件渲染呢? 是的,這是可能的。 例如,讓咱們看看以前的 List 組件,它顯示了一個列表、一個空文本或者什麼都沒有:

function List({ list }) {
  const isNotAvailable = !list;
  const isEmpty = !list.length;
  return (
    <div> {isNotAvailable ? <p>Sorry, the list is not there.</p> : (isEmpty ? <p>Sorry, the list is empty.</p> : <div>{list.map(item => <Item item={item} />)}</div> ) } </div> ); } 複製代碼

它能夠工做,但我建議避免嵌套條件渲染,由於他們是冗長的,這使得它不太可讀。 試試下面的解決方案:

  • 僅在主返回語句以前使用 if 語句的守衛模式
  • 將組件拆分爲多個組件,而每一個組件負責本身的非嵌套條件渲染

使用HOC的條件渲染

高階組件(Higher-Order Components,HOCs)是 React 中條件渲染的完美匹配。 Hoc 能夠幫助處理多個使用場景,可是一個場景多是使用條件渲染來改變組件的外觀。 讓咱們看看一個顯示元素或組件的 HOC:

// Higher-Order Component
function withLoadingIndicator(Component) {
  return function EnhancedComponent({ isLoading, ...props }) {
    if (!isLoading) {
      return <Component {...props} />;
    }
    return (
      <div>
        <p>Loading</p>
      </div>
    );
  };
}
const ListWithLoadingIndicator = withLoadingIndicator(List);
function App({ list, isLoading }) {
  return (
    <div>
      <h1>Hello Conditional Rendering</h1>
      <ListWithLoadingIndicator isLoading={isLoading} list={list} />
    </div>
  );
}
複製代碼

在這個示例中,List 組件能夠專一於渲染列表。 它沒必要擔憂加載狀態。 一個 HOC 在您的實際組件中隱藏了全部的噪音。 最終,您能夠添加多個高階組件(組合) ,以隱藏多個條件渲染邊緣狀況。 做爲 hoc 的替代品,你也可使用 render prop 支持條件渲染。

React中的if else組件

最後但並不是最不重要的是,有外部庫處理標記級別上的條件渲染。 他們添加了控制組件,以便在沒有 JS 的狀況下啓用條件渲染:

<Choose>
  <When condition={isLoading}>
    <div><p>Loading...</p></div>
  </When>
  <Otherwise>
    <div>{list.map(item => <Item item={item} />)}</div>
  </Otherwise>
</Choose>
複製代碼

不少人認爲React(包括JSX)是他們的首選庫,由於他們能夠在JSX中使用純HTML和JS處理渲染。

我但願這個 React 教程對您學習條件渲染有所幫助。 若是你喜歡它,請與你的朋友分享。 最後,我爲你準備了一個所有條件渲染的備忘單:

  • if
    • 最基本的條件渲染
    • 用於在一個渲染中提早返回(守衛模式)
    • 不能在 return 語句和 JSX 中使用(自調用函數除外)
  • if-else
    • 不多用它,由於它太冗長了
    • 可使用三元運算符或邏輯 && 運算符替代
    • 不能在 return 語句和 JSX 中使用(自調用函數除外)
  • 三元運算符
    • 用它代替 if-else 語句
    • 它能夠在 JSX 和 return 語句中使用
  • 邏輯 && 操做符
    • 當三元運算的一端返回 null 時使用它
    • 它能夠在 JSX 和 return 語句中使用
  • switch case
    • 避免使用它,由於它太冗長
    • 能夠用枚舉替代
    • 不能在 return 語句和 JSX 中使用(自調用函數除外)
  • 枚舉
    • 使用它來進行基於多個狀態的條件渲染
    • 完美地映射多個條件
  • 嵌套條件渲染
    • 爲了可讀性,避免使用它們
    • 能夠拆分組件、使用 if 語句或者使用 hoc 替代
  • HOCs(高階組件)
    • 組件能夠專一於它們的主要目的
    • 使用 HOC 屏蔽條件渲染
    • 使用多個可組合 hoc 屏蔽多個條件渲染
  • 外部模板組件
    • 避免使用它們,並適應 JSX 和 JS
相關文章
相關標籤/搜索