iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
Modern Web

剛入行就一人重新打造公司前端系統?系列 第 8

Day 8 - 製作共用元件很難嗎?從避免過度依賴條件渲染開始!

  • 分享至 

  • xImage
  •  

最初我以為共用元件的設計應該沒哪麼難,不就像設計 function 時,會重複用到的就把它拆出來就好了,元件也是一樣的道理吧,但隨著情境越來越多樣,要適用的情境越來越複雜,才發現原來我完全不懂「抽象化」,真正設計出能夠多次重用的元件,實際上比我想像的要難得多。

在製作共用元件上時的困擾包括:

  • 如果支援 A、支援 B、又支援 C,不會變得超級複雜嗎?
  • 很類似的元件,是該拆成多個還是用一個元件來支援多個變體(variants)?
  • props 應該要傳哪些東西才合適?
  • 一個元件到底要多大或多小,太小不會分成很多層嗎?
  • state 該設置在哪一層?

這幾天的文章將探討如何解決設計共用元件時遇到的這些問題。首先,我們來定義一下什麼是「好」的共用元件。

「好」的共用元件

共用元件是指那些能夠在多個地方被重複使用的元件,以下是我整理的「好」的共用元件該有的特性:

  • 高重用性(Reusability):元件應該能夠適用於多個不同的情境。
    • 高重用性的元件通常是純粹、可預測的、通用的(generic),並且不應該包含複雜的商業邏輯(business logic)。
    • 避免副作用(side effect),例如元件內不應該包含與外部資料互動的邏輯(如 API 請求),這些邏輯應該透過 props 傳遞。
  • 高可配置性(Configurability):元件應能透過 props 傳遞資料或樣式來進行配置,避免硬編碼(hardcoding)。
    • 動態文本等應通過 props 傳入,而不是直接在元件內部硬編碼。
  • 單一職責原則(Single Responsibility):每個元件應該只專注於一項任務,保持其功能專一性。

避免過度依賴條件渲染

前面提到如果支援 A、支援 B、又支援 C,不會變得超級複雜嗎?如果有遇到這樣的困擾,代表在為了支援多個情境可能用大量的條件渲染邏輯寫在元件裡面,像是用 ? : 條件運算符或 if else 來處理不同的情況,這樣做會讓元件變得非常複雜、不易維護,此時也表示元件設計得不夠抽象化。

// ❌ 錯誤範例:過度依賴條件渲染

const IdolCard = ({ role }) => {
  return (
    <div
      className={
        role === "Shiver"
          ? "bg-blue-500"
          : role === "Frye"
          ? "bg-yellow-400"
          : role === "Big Man"
          ? "bg-red-400"
          : "bg-black"
      }
    >
      <p>
        {role === "Shiver"
          ? "莎莎"
          : role === "Frye"
          ? "曼曼"
          : role === "Big Man"
          ? "鬼福"
          : ""}
      </p>
    </div>
  );
};

const App = () => (
  <div>
    <IdolCard role="Shiver" />
    <IdolCard role="Frye" />
    <IdolCard role="Big Man" />
  </div>
);

那其實最簡單的解決方式,就是昨天 Day 7 - 打造靈活的元件設計 —— 將樣式傳進元件 中提到的使用 樣式傳入元件render props 的方式,來提高元件的抽象度~

// ⭕️ 正確範例:使用 Render Props

const IdolCard = ({ render }) => {
  return render();
};

const App = () => {
  return (
    <div>
      <IdolCard 
        render={() => (
          <div className="bg-blue-500 p-4">
            <p>莎莎</p>
          </div>
        )}
      />
      <IdolCard 
        render={() => (
          <div className="bg-yellow-400 p-4">
            <p>曼曼</p>
          </div>
        )}
      />
      <IdolCard 
        render={() => (
          <div className="bg-red-400 p-4">
            <p>鬼福</p>
          </div>
        )}
      />
    </div>
  );
};

codesandbox

參考資料


上一篇
Day 7 - 打造靈活的元件設計 —— 將樣式傳進元件
下一篇
Day 9 - 透過 Container/Presentational Pattern 來實現功能與樣式分離
系列文
剛入行就一人重新打造公司前端系統?27
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言