如何規劃與拆分元件?從 UI 切割建立模組思維
更新日期: 2025 年 4 月 14 日
《React 元件基礎介紹》:
- React 的開發邏輯:為什麼現代前端要用元件?
- React 元件是什麼?畫面積木的基本單位
- 什麼是元件樹?理解元件的父子與巢狀結構
- 撰寫第一個 React 元件:函式型元件入門
- 如何規劃與拆分元件?從 UI 切割建立模組思維
- 元件之間如何傳資料?Props 教學入門
- 初學者也能懂!React children 全解析與實戰教學
- React 元件可以有自己的資料?state 基礎觀念與使用
- 什麼是 prop drilling?當資料傳遞變成麻煩
- Context API 是什麼?解決 prop drilling 的痛點
- 比 Context 更好用的選擇?認識第三方狀態管理工具
在閱讀本文前,建議先閱讀《JSX 基礎介紹》
你可能曾經這樣寫 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)
大駝峰命名法是指每個單字首字母皆大寫,例如 TodoApp
、TodoList
,這是 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、甚至設計系統,也都能更順手!