精讀《React 八種條件渲染》

1 引言

本期精讀的文章是:8 React conditional rendering methodshtml

介紹了八種 React 條件渲染方式。react

模版條件渲染很是常見,遇到的時候每每會隨機選擇一種方式使用,那麼怎麼寫會有較好的維護性呢?先一塊兒瞭解下有哪八種條件渲染方式吧!git

2 概述

IF/ELSE

既然 JSX 支持 js 與 html 混寫,那麼交替使用就能解決條件渲染的問題:程序員

function render() {
  if (renderComponent1) {
    return <Component1 />;
  } else {
    return <div />;
  }
}

return null

若是不想渲染空元素,最好使用 null 代替空的 divgithub

function render() {
  if (renderComponent1) {
    return <Component1 />;
  } else {
    return null;
  }
}

這樣對 React 渲染效率有提高。typescript

組件變量

將組件賦值到變量,就能夠在 return 前任意修改它了。編程

function render() {
  let component = null;

  if (renderComponent1) {
    component = <Component1 />;
  }

  return component;
}

三元運算符

三元運算符的語法以下:函數

condition ? expr_if_true : expr_if_false

用在 JSX 上也很方便:spa

function render() {
  return renderComponent1 ? <Component1 /> : null;
}

但三元運算符產生嵌套時,理解成本會變得很高。code

&&

這個是最經常使用了,由於代碼量最少。

function render() {
  return renderComponent1 && <Component1 />;
}

IIFE

IIFE 含義是當即執行函數,也就是以下代碼:

(function myFunction(/* arguments */) {
  // ...
})(/* arguments */);

當深陷 JSX 代碼中,又想寫一大塊邏輯時,除了回到上方,還可使用 IIFE:

function render() {
  return (
    <div>
      {(() => {
        if (renderComponent1) {
          return <Component1 />;
        } else {
          return <div />;
        }
      })()}
    </div>
  );
}

子組件

這是 IIFE 的變種,也就是把這段當即執行函數替換成一個普通函數:

function render() {
  return (
    <div>
      <SubRender />
    </div>
  );
}

function SubRender() {
  if (renderComponent1) {
    return <Component1 />;
  } else {
    return <div />;
  }
}

IF 組件

作一個條件渲染組件 IF 代替 js 函數的 if

<If condition={true}>
  <span>Hi!</span>
</If>

這個組件實現也很簡單

const If = props => {
  const condition = props.condition || false;
  const positive = props.then || null;
  const negative = props.else || null;

  return condition ? positive : negative;
};

高階組件

高階組件,就是返回一個新組件的函數,而且接收一個組件做爲參數。

那麼咱們就能在高階組件裏寫條件語句,返回不一樣的組件便可:

function higherOrderComponent(Component) {
  return function EnhancedComponent(props) {
    if (condition) {
      return <AnotherComponent {...props} />;
    }

    return <Component {...props} />;
  };
}

3 精讀

這麼多方法都能實現條件渲染,那麼重點在於可讀性與可維護性。

好比經過調用函數實現組件渲染:

<div>{renderButton()}</div>

看上去仍是比較冗餘,若是使用 renderButton getter 定義,咱們就能夠這麼寫它:

<div>{button}</div>

其實咱們想要的就是 button,而不是 renderButton。那麼還能夠進一步,乾脆封裝成 JSX 組件:

<div>
  <Button />
</div>

是否要付出這些努力,取決於應用的複雜度。若是應用複雜度很是高,那你應當儘可能使用最後一種封裝,讓每一個文件的邏輯儘可能獨立、簡單。

若是應用複雜度比較低,那麼注意不要過分封裝,以避免把本身繞進去。

因此看來這又是一個沒有固定答案的問題,選擇何種方式封裝,取決於應用複雜度。

應用複雜度

對任何代碼封裝,都會增長這段 鏈接邏輯 的複雜度。

假定不管如何代碼的複雜度都是恆定不變的,下面這段代碼,鏈接複雜度爲 0,而對於 render 函數而言,邏輯複雜度是 100:

function render() {
  if (renderComponent) {
    return isOk ? <Component1 /> : <Component2 />;
  } else {
    return <div />;
  }
}

下面這段代碼拆成了兩個函數,邏輯複雜度對 render SubComponent 來講都是 50,但鏈接複雜度是 50:

function render() {
  if (renderComponent) {
    return <SubComponent>;
  } else {
    return <div />;
  }
}

function SubComponent() {
  return isOk ? <Component1 /> : <Component2 />
}

能夠看到,咱們經過函數拆分,下降了每一個函數的邏輯複雜度,但卻提升了鏈接複雜度。

下面來作一個比較,咱們假設一個正常的程序員,能夠一次性輕鬆記憶 10 個函數。若是再多,函數之間的調用關係就會讓人摸不着頭腦。

應用較小時

在應用代碼量比較小時,假設一共有 10 個函數,若是作了邏輯抽象,拆分出了 10 個子函數,那麼總邏輯複雜度不變,函數變成了 20 個。

此時小王要修改此項目,他須要找到關鍵代碼的位置。

若是沒有作邏輯抽象,小王一會兒就記住了 10 個函數,而且很快完成了需求。

若是應用作了邏輯抽象,他須要理解的邏輯複雜度是不變的,可是要讀的函數變成了 20 個。小王須要像偵探同樣在線索中不斷跳轉,他仍是隻找了 10 個關鍵函數,但一共也就 20 個函數,邏輯並不複雜,這值得嗎?

小王內心可能會嘀咕:簡單的邏輯瞎抽象,害我文件找了半天!

應用較大時

此時應用代碼量比較大,假設一共有 500 個函數,咱們不考慮抽象後帶來的複用好處,假設都沒法複用,那麼作了邏輯抽象後,那麼總邏輯複雜度不變,函數變成了 1000 個。

此時小王接到了需求,終於維護了一個大項目。

小王知道這個項目很複雜,從一開始就沒以爲能理解項目全貌,因此把本身看成一名偵探,準備一步步探索。

如今有兩種選擇,一種是在未作邏輯抽象時探索,一種是在作過邏輯抽象後探索。

若是沒作邏輯抽象,小王須要面對 500 個這種函數:

function render() {
  if (renderComponent) {
    return isOk ? <Component1 /> : <Component2 />;
  } else {
    return isReady ? <Component3 /> : <Component4 />;
  }
}

若是作了邏輯抽象,小王須要面對 1000 個這種函數:

function render() {
  if (renderComponent) {
    return <Component1And2 />;
  } else {
    return <Component3And4 />;
  }
}

在項目龐大後,總函數數量並不會影響對線索的查找,而總線索深度也幾乎老是固定的,通常在 5 層左右。

小王理解 5 個或 10 個函數成本都差很少,但沒有作邏輯抽象時,這 5 個函數各自參雜了其餘邏輯,反而影響對函數的理解。

這時作邏輯抽象是合適的。

4 總結

因此總的來講,筆者更傾向使用子函數、子組件、IF 組件、高階組件作條件渲染,由於這四種方式都能提升程序的抽象能力。

每每抽象後的代碼會更具備複用性,單個函數邏輯更清晰,在切面編程時更利於理解。

當項目很簡單時,整個項目的理解成本都很低,抽象帶來的複雜度反而讓項目變成了須要切面編程的時候,就得不償失了。

總結一下:

  • 當項目很簡單,或者條件渲染的邏輯確認沒法複用時,推薦在代碼中用 && 或者三元運算符、IIFE 等直接實現條件渲染。
  • 當項目很複雜時,儘可能都使用 子函數、子組件、IF 組件、高階組件 等方式作更有抽象度的條件渲染。
  • 在作邏輯抽象時,考慮下項目的複雜度,避免由於抽象帶來的成本增長,讓本能夠總體理解的項目變得支離破碎。

5 更多討論

討論地址是: 精讀《React 八種條件渲染》 · Issue #90 · dt-fe/weekly

若是你想參與討論,請點擊這裏,每週都有新的主題,週末或週一發佈。

相關文章
相關標籤/搜索