iT邦幫忙

2026 iThome 鐵人賽

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

從 UI/UX 麻瓜到工程魔法師|從讀懂程式開始系列 第 6

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

  • 分享至 

  • xImage
  •  

上一篇講到 State 和 Props。

當所有內容都還寫在同一個 Component 裡時,其實不太會感覺到資料傳遞有多麻煩。

但真正開始拆 Component 之後,問題就會突然變明顯:

這份資料是誰的?

這個 Component 需要哪些資料?

要不要從 Parent 傳進來?

誰負責修改?

而這也是我後來才慢慢發現的一件事:

拆 Component,不只是把程式碼切成很多檔案。

真正要拆的是:

責任
+
資料依賴

一開始,我只知道「檔案太長就拆」

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

檔案很長
↓
太亂
↓
拆 Component

例如一個 Detail Page:

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

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

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

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

隨著功能增加,可能又繼續塞:

DetailPage

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

這時候最直覺的感覺就是:

好長,我要拆。

但後來才發現:

行數很多,只是一個訊號,不是判斷 Component 要不要拆的唯一標準。


我現在比較會先看「這一塊負責什麼」

例如一個頁面裡有:

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

這些區塊都有一個共同點:

可以很清楚說出它的責任。

例如:

BasicInfo
→ 負責基本資訊

ProductInfo
→ 負責商品相關內容

DocumentInfo
→ 負責文件資訊

如果一塊 UI 已經可以很清楚地被命名,而且有自己相關的資料與畫面邏輯,就可以開始考慮拆成 Component。

例如:

function DetailPage() {
  return (
    <>
      <BasicInfo data={detail} />

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

      <DocumentInfo
        documents={detail.documents}
      />
    </>
  );
}

這時候 Parent 的責任會變得比較清楚:

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

而:

ProductInfo

就只需要專心處理:

Product 相關資料

拆完 Component,我反而更容易看懂資料流

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

以前全部塞在同一個檔案時:

API Response
↓
很多變數
↓
很多 function
↓
很多 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
├─ 基本資料
├─ 商品資料
└─ 文件資料

但功能持續增加後,慢慢變成:

Page
├─ API Request
├─ Permission
├─ Form
├─ Tab
├─ Table
├─ Modal
├─ Button
├─ 各種資料處理
└─ 各種顯示邏輯

後來開始依照不同畫面與功能責任拆開:

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

但真正開始拆後,我才發現:

把 JSX 搬出去其實只是第一步。

接著馬上會遇到:

這個 Component 到底需要哪些資料?

哪些資料 Parent 已經有?

哪些 Props 要傳進去?

誰負責修改?

哪些資料很多 Component 都需要?

這時候才真的接回上一篇講的:

State
↓
Props
↓
Child Component

拆之前,我現在會先畫一張簡單的圖

比起一開始就開始剪程式碼,我現在比較想先整理責任:

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

然後問:

哪些資料只有這個 Component 需要?
↓
留在 Component

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

哪些資料很多不同 Component 都需要?
↓
可能要再考慮其他共享方式

這時候 Component 拆分就不再只是:

「把程式碼搬到另一個檔案。」

而是:

重新整理畫面責任
↓
整理資料依賴
↓
重新確認資料流

今天真正想記的是:不要用行數決定一切

以前:

檔案很長
↓
拆

現在比較會多想一層:

這一塊負責什麼?
↓
它需要哪些資料?
↓
它的邏輯是不是已經相對獨立?
↓
拆出去後,責任會不會更清楚?

所以 Component 拆分對我來說,已經不只是整理畫面。

而是:

把「誰負責什麼」這件事說清楚。

當 Component 一層一層拆下去之後,下一個問題也很快會出現:

Parent
↓ Props
Child
↓ Props
GrandChild
↓ Props
GrandGrandChild

如果中間的 Component 根本不需要這份資料,卻只是負責一直往下傳,就會開始出現另一個問題:

Props 到底要傳幾層?

下一篇就來看:

Props 傳到懷疑人生時,Context 到底是在解決什麼?


上一篇
Day 05|State 跟 Props 到底差在哪?這份資料到底是誰的?
下一篇
Day 07|Props 傳到懷疑人生時,Context 到底是在解決什麼?
系列文
從 UI/UX 麻瓜到工程魔法師|從讀懂程式開始9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言