iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
佛心分享-IT 人職涯歷練

從 UI/UX 麻瓜到工程魔法師 | 從看不懂咒語開始系列 第 6

Day 06|Component 不是拆越多越好:一個頁面到底什麼時候該拆?

  • 分享至 

  • xImage
  •  

剛開始寫 React 時,我對 Component 的理解很單純:

畫面太大,就拆。

於是看到一個很長的檔案,很自然會覺得:

500 行
↓
太長
↓
拆 Component

但真的進到專案後才發現,事情沒有這麼單純。

有些 Component 雖然不長,卻同時處理很多不同責任;

有些 Component 看起來很長,但裡面的內容其實高度相關,硬拆反而讓資料到處傳。

所以我後來開始把問題從:

「這個檔案是不是太長?」

改成:

「這一塊是不是已經有自己的責任?」


從一個 Detail Page 開始

假設現在有一個 Detail Page:

function DetailPage() {
  return (
    <>
      <BasicInfo />
      <ProductInfo />
      <DocumentInfo />
      <PerformanceInfo />
    </>
  );
}

一開始它可能不是這麼漂亮。

比較可能是所有東西都直接寫在同一個檔案:

function DetailPage() {
  return (
    <>
      <Card title="Basic Information">
        {/* 很多欄位 */}
      </Card>

      <Card title="Product Information">
        {/* 很多欄位 */}
      </Card>

      <Table
        columns={...}
        dataSource={...}
      />

      <Card title="Document">
        {/* 又很多欄位 */}
      </Card>
    </>
  );
}

功能繼續增加之後,還可能出現:

DetailPage

├─ API Request
├─ Form
├─ Basic Information
├─ Product Information
├─ Table
├─ Document
├─ Permission
├─ Button
├─ Modal
└─ 各種處理 function

這時候真正麻煩的,不只是「檔案很長」。

而是我想修改其中一塊時,要在大量不相關的程式碼裡尋找。

例如只是想修改:

Product Information

卻要先穿過:

API
↓
Permission
↓
Basic Info
↓
各種 function
↓
終於找到 Product

這時候就開始出現拆分的價值。


我現在會先看「責任」,而不是行數

例如:

DetailPage
│
├─ BasicInfo
├─ ProductInfo
├─ DocumentInfo
└─ PerformanceInfo

這些區塊都有一個特徵:

我可以清楚說出「它負責什麼」。

例如:

BasicInfo
→ 負責顯示基本資料

ProductInfo
→ 負責商品相關內容

DocumentInfo
→ 負責文件資訊

當一塊 UI 已經可以被清楚命名,而且擁有自己的資料與畫面邏輯時,就很適合考慮拆成 Component。

例如:

function DetailPage() {
  return (
    <>
      <BasicInfo data={detail} />
      <ProductInfo products={detail.products} />
      <DocumentInfo documents={detail.documents} />
    </>
  );
}

這時候 DetailPage 的責任也開始變得比較清楚:

DetailPage
↓
取得 / 管理主要資料
↓
把需要的資料交給不同 Component

而子 Component:

ProductInfo
↓
只需要關心 Product

這其實就接回上一篇的 State 和 Props。


拆 Component 之後,我反而開始看懂資料流

這是我在實際專案裡很有感的一件事。

以前所有東西都放在同一個檔案時:

API Response
↓
一大堆變數
↓
一大堆 JSX

我其實很難看出:

哪一份資料到底是誰在用?

但拆 Component 時,就會被迫回答:

BasicInfo 需要什麼?

ProductInfo 需要什麼?

DocumentInfo 需要什麼?

例如:

<ProductInfo
  products={detail.products}
  currency={detail.currency}
/>

光看 Props 就開始能知道:

ProductInfo
│
├─ products
└─ currency

它依賴的資料比較明確。

所以拆 Component 不只是整理檔案。

對我來說,它還有另一個很重要的作用:

幫助我重新整理每個區塊真正需要哪些資料。


但不是看到一小塊 UI 就全部拆

學到 Component 之後,也很容易走到另外一個極端。

例如:

<div>
  <Title />
  <Name />
  <Price />
  <Button />
</div>

然後每一個都建立一個檔案:

Title.tsx
Name.tsx
Price.tsx
Button.tsx

最後想找一個畫面,反而要一直跳檔案。

所以:

Component 不是拆越多越好。

我現在會先問幾個問題:

① 這一塊有明確的責任嗎?

② 它是不是有自己的一組資料或邏輯?

③ 未來修改它時,能不能大部分只關心這個 Component?

④ 這一塊是不是會被重複使用?

其中第 ④ 點只是其中一個理由。

以前我會以為:

「只有重複使用才需要拆 Component。」

但後來才發現,即使一個 Component 只使用一次,只要它有獨立責任,拆開依然可能讓程式更容易閱讀與維護。


一個我實際遇過的情況

我曾經遇過一個頁面,功能一路增加之後,越來越多內容都集中在同一個地方。

後來開始按照畫面與功能責任,把不同區塊拆出去:

Page
│
├─ Info Section
├─ Product Section
├─ Document Section
└─ Other Section

但拆完並不是結束。

真正麻煩的問題反而接著出現:

這個 Component 需要哪些資料?

這份資料要從 Parent 傳嗎?

誰負責修改?

有沒有資料其實很多 Component 都需要?

也就是上一篇提到的:

State
↓
Props
↓
Child Component

開始真的出現在實際開發裡。

這時候我才慢慢理解:

拆 Component 不是把 JSX 剪下來貼到另一個檔案而已。

真正的拆分還包含:

責任重新分配
+
資料依賴重新整理

我現在會先畫這張圖

遇到比較大的頁面時,比起直接開始搬程式碼,我會先簡單整理:

DetailPage
│
├─ BasicInfo
│   └─ basicData
│
├─ ProductInfo
│   ├─ products
│   └─ currency
│
└─ DocumentInfo
    └─ documents

然後再問:

哪些資料只有自己需要?
↓
留在 Component

哪些資料 Parent 已經有?
↓
透過 Props 傳入

哪些資料很多深層 Component 都需要?
↓
可能要再想其他管理方式

最後這個「很多 Component 都需要」的問題,就會帶出下一個我以前看到很害怕的東西:

useContext(...)

以前我看到 Context,只覺得:

又多一個 React 咒語。

但真的遇到 Component 一層一層拆下去之後,才開始理解它到底想解決什麼。

下一篇就來看:

為什麼 Props 傳一傳,最後會傳到懷疑人生?Context 到底是在解決什麼問題?


上一篇
Day 05|State 跟 Props 到底差在哪?這份資料到底是誰的?
系列文
從 UI/UX 麻瓜到工程魔法師 | 從看不懂咒語開始6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言