如何規劃與拆分元件?從 UI 切割建立模組思維

更新日期: 2025 年 4 月 14 日

你可能曾經這樣寫 React 程式:

return (
  <div>
    <h1>標題</h1>
    <input />
    <button>新增</button>
    <ul>
      {todos.map(todo => (
        <li>{todo}</li>
      ))}
    </ul>
  </div>
);

一開始寫起來很快,但隨著畫面變多、功能變複雜,這個元件就會變得又長又難懂。

✅ 解法就是:把元件拆成小模組,讓每個元件只負責一件事情。

這篇文章會教你 如何從 UI 畫面出發,規劃與拆分元件,讓你的程式碼更清楚、更容易維護。


什麼是元件拆分?先建立正確觀念

在 React 中,我們的目標不是「從頭到尾寫一整頁畫面」,而是把整個畫面切成許多可組合的小模組,這些模組就叫做 元件(Component)

元件 = UI 模組的最小單位

你可以把每個元件想像成是一塊 UI 積木:

每塊積木專注處理自己的畫面、資料與事件,最後再把這些積木組裝起來,變成完整的網站。

舉個簡單的例子,如果你要做一個待辦事項的頁面(Todo App),畫面大概長這樣:

  • 一個標題:「我的待辦清單」
  • 一個輸入欄位 + 按鈕,新增待辦事項
  • 一個清單,列出所有待辦事項

這時候我們可以這樣切元件:

<TodoApp>
  ├─ <Title />         // 顯示標題
  ├─ <TodoForm />      // 管理輸入欄位與新增按鈕
  └─ <TodoList />      // 顯示所有待辦項目
        └─ <TodoItem /> // 每一個待辦項目

這種拆法就像樂高一樣,把複雜的東西變成一塊一塊、好懂又好用的模組。

重點提醒:元件不只處理畫面

元件除了顯示 UI,也可以包含:

  • 狀態(state):例如輸入框的文字內容
  • 事件(event):例如點按鈕時觸發新增待辦
  • 資料(props):從外層傳進來的資訊

所以說元件的角色就像一個「獨立的、負責任的 UI 小功能區塊」,你可以放心交辦它一件事,它會自己處理好。


為什麼要拆元件?四大好處幫你快速成長

有些初學者會想:「一開始就拆元件是不是太麻煩?不就寫在一起比較快?」

但實際上,一開始拆對元件,可以省下你之後 10 倍的麻煩!

以下是你會得到的好處:

提升程式碼易讀性

當你把每個區塊都變成小元件,主元件就只剩下大致的結構,像這樣:

function App() {
  return (
    <div>
      <Header />
      <TodoForm />
      <TodoList />
    </div>
  );
}

是不是一眼就能看懂這個畫面是怎麼構成的?
對比那種幾百行寫在一起的混亂程式碼,可讀性馬上提升 100 倍

提高重用性

當你寫了一個設計良好的元件,未來不同地方都可以拿來直接用,不用重複開發。

例如:

  • <Button /> 按鈕元件,可以在登入頁、註冊頁、設定頁共用
  • <Modal /> 彈跳視窗,任何地方都能呼叫來顯示提示或表單

這種「一次開發,多處使用」的好處,讓你越寫越快、開發效率暴增。

更容易除錯與測試

小元件功能單一,錯誤範圍也小。

如果某個功能出錯,你只要檢查該元件就好,不需要從整頁程式裡海撈蛛絲馬跡。

此外,小元件也更容易寫單元測試(unit test),確保每個功能都穩定無誤。

更適合多人協作開發

如果元件都拆好了,不同成員就可以同時開發:

  • 小明負責 <TodoForm />
  • 小美負責 <TodoList />
  • 阿哲負責 <TodoItem />

大家寫完後,組起來就是一個完整畫面!

這樣不但節省時間,也減少合併衝突,是大型專案或團隊合作的必備技能。


如何從 UI 畫面切出元件?

掌握 3 步驟,讓你不再卡在「要不要拆」的選擇障礙

在 React 開發中,「畫面怎麼切元件?」是每個人都會遇到的問題。

這裡提供一套簡單好用的思考流程,幫助你從畫面觀察到實際拆分元件,養成模組化思維!

步驟 1:觀察畫面結構

先不急著寫程式,先觀察整個 UI 的構成。問自己幾個問題:

  • 這個畫面有哪些明顯的區塊?
  • 哪些是有重複結構的?(像是清單、表格)
  • 使用者的互動集中在哪些地方?

✅ 範例畫面:Todo App

假設我們要做一個最簡單的 Todo App,畫面大概像這樣:

步驟 2:畫出 UI 區塊(元件草圖)

將上面觀察到的畫面區塊,用文字或圖示簡單列出來:

<App>
  ├─ <Header />         標題區
  ├─ <TodoForm />       表單區:輸入 + 按鈕
  └─ <TodoList>         清單區
        ├─ <TodoItem />
        ├─ <TodoItem />
        └─ ...

小技巧: 用資料結構的方式去「排元件樹」,會幫助你思考資料怎麼流動(例如:App → TodoList → TodoItem)。

這步驟的重點不是畫得漂亮,而是把畫面「結構化」,讓你不會迷失在一堆 <div> 裡。

步驟 3:依據「功能單一原則」拆元件

React 推崇 單一職責原則(Single Responsibility Principle)

意思是:「一個元件只負責一件事。」

讓我們回到上面畫的結構,來說明每個元件的職責:

元件名稱功能說明
<Header />負責顯示頁面標題:「我的待辦清單」
<TodoForm />管理輸入欄位的值、處理點擊「新增」時的邏輯
<TodoList />接收 todos 陣列,並用 .map() 產生清單項目
<TodoItem />顯示一項待辦項目(如:買牛奶)+ 是否完成 + 刪除功能

這樣拆完後,每個元件都變得短小精幹、職責明確,即使是初學者也能輕鬆維護!


怎麼判斷要不要拆元件?

拆元件的技巧沒有唯一標準,但以下幾個「雷達指標」能幫助你判斷是否該拆:

是否有重複使用的潛力?

如果一段 UI 在多個頁面會出現,務必抽成元件

✅ 例子:

  • <Button />:通用按鈕樣式與事件處理
  • <Card />:可重用的卡片樣板(商品、課程、影片等)

🛑 若你在多個地方複製貼上一樣的 JSX,那就該抽出元件了!

是否程式碼太長?

如果一個元件長達 100 行以上,很可能混雜太多邏輯,建議拆分為子元件

✅ 做法建議:

  • UI 部分太長 ➜ 拆成 Presentation Component
  • 處理流程太複雜 ➜ 拆出 custom hook 或 logic-only component

是否功能不單一?

如果你在一個元件裡,同時看到「畫面處理 + 表單驗證 + API 請求」,那就太雜了!

建議這樣拆:

  • <LoginForm> 負責顯示表單
  • useLogin() 抽出登入邏輯
  • <LoginContainer> 負責處理整合

是否難以測試或修改?

一個元件只要一改就牽一髮動全身,代表它耦合性太高。

✅ 解法:

  • 簡化元件的 props,只傳進需要的資料
  • 把一些事件邏輯抽出去做 callback 或 hook

命名與檔案規劃的實務建議

在 React 專案中,良好的命名規則與檔案規劃不只是為了整齊美觀,更是幫助日後的維護、擴充與團隊協作變得更順暢。

命名習慣:建議使用大駝峰(PascalCase)

大駝峰命名法是指每個單字首字母皆大寫,例如 TodoAppTodoList,這是 React 社群中約定俗成的命名方式,尤其對於「元件檔案名稱」來說幾乎是標準。

 TodoApp.jsx
 TodoList.jsx
 TodoItem.jsx

📌 為什麼這麼做?

  • 一眼就看出這是「元件」,不是函式或工具函數。
  • 和 HTML tag(小寫開頭)區分開來。
  • 保持一致,團隊開發更容易協作。

檔案規劃建議:每個元件一個檔案

將每個元件分開放在獨立檔案中,是 React 專案中最基本也最實用的管理方式。

/components
  ├── TodoApp.jsx
  ├── TodoList.jsx
  ├── TodoItem.jsx
  └── TodoForm.jsx

這樣做的好處是:

  • ✅ 更容易找檔案與除錯。
  • ✅ 單一職責原則(每個元件負責一個功能)。
  • ✅ 可以搭配版本控制,單一元件修改記錄清楚。

如果元件變複雜,建議使用資料夾方式管理

當一個元件內部結構越來越複雜,例如包含自己的 CSS 模組、測試檔案、Hook、子元件等,可以這樣拆分:

/components/TodoItem/
  ├── index.jsx           # 元件主體
  ├── styles.module.css   # 專屬樣式
  └── useTodoStatus.js    # 專屬 Hook(選擇性)

🔍 index.jsx 這個命名的好處是:

  • 引入的時候可以簡化成: import TodoItem from './components/TodoItem'; 而不需要寫到 ./components/TodoItem/index.jsx

元件拆分實例:Todo App

這是一個經典的練習案例,用來練習元件切割與資料傳遞(props)的最佳起手式。

App.jsx

整個 App 的入口,負責組合畫面與管理狀態。

function App() {
  const [todos, setTodos] = useState([]);

  const addTodo = (text) => {
    setTodos([...todos, text]);
  };

  const deleteTodo = (index) => {
    setTodos(todos.filter((_, i) => i !== index));
  };

  return (
    <div>
      <h1>我的待辦清單</h1>
      <TodoForm onAdd={addTodo} />
      <TodoList todos={todos} onDelete={deleteTodo} />
    </div>
  );
}

TodoForm.jsx

負責處理輸入與新增按鈕的邏輯。

function TodoForm({ onAdd }) {
  const [text, setText] = useState('');

  const handleSubmit = () => {
    if (text.trim()) {
      onAdd(text.trim());
      setText('');
    }
  };

  return (
    <div>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
        placeholder="輸入新待辦"
      />
      <button onClick={handleSubmit}>新增</button>
    </div>
  );
}

TodoList.jsx

負責渲染待辦清單,並將每一項交由 <TodoItem /> 處理。

function TodoList({ todos, onDelete }) {
  return (
    <ul>
      {todos.map((todo, index) => (
        <TodoItem key={index} text={todo} onDelete={() => onDelete(index)} />
      ))}
    </ul>
  );
}

TodoItem.jsx

單一的待辦項目,顯示文字與刪除按鈕。

function TodoItem({ text, onDelete }) {
  return (
    <li>
      {text} <button onClick={onDelete}>刪除</button>
    </li>
  );
}

結語:元件設計,從 UI 思維開始

初學者常常擔心:「這個畫面我該怎麼拆?」

別擔心,畫出 UI 框架、從功能切分,就能自然地拆出元件。這不只是 React 的技巧,更是現代前端的核心能力。

你越熟練這種「模組化思維」,未來寫 Vue、Svelte、甚至設計系統,也都能更順手!

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *