當專案規模逐漸擴大,傳統手動抓取 DOM 節點並修改內容的方式,往往會讓程式碼變得難以維護且充滿潛在的 Bug。為了解決這個問題,現代前端開發引入了「資料驅動 (State-driven)」的概念。本章節將引導你捨棄過往直接操作 HTML 標籤的習慣,轉而將應用程式拆分為掌管真相的「狀態 (State)」與負責繪製畫面的「渲染 (Render)」。學會這套戰略指揮系統,你將能更優雅地處理複雜的 UI 互動,為邁向現代前端框架打下堅實的基礎。
Day 27: 【戰略指揮】資料驅動 (State-driven) —— 從動手肌肉,到下達腦袋指令
本文同步分享於2026鐵人賽:JS 核心重構:勇者轉職傳說
「導師,我不想再手動改 HTML 了,真的好累。」
聽著,孩子。當你的小隊只有 3 個人時,你確實可以一個一個拍肩膀下令。但當你指揮的是萬人大軍,你需要的不是體力,而是 「戰略系統」。
今天,我們不學新語法。我們要學習如何 「換一顆腦袋」。這是你這 30 天修煉中最痛苦的一天,卻也是你脫胎換骨的一天。
🛡️ 【公會大廳:導師的修煉導讀】
「導師,Day 18 的待辦清單專案,我加了一個『編輯功能』後,程式碼就炸開了...」
我看著那疊厚厚的代碼,裡面充滿了 document.getElementById、appendChild、innerHTML = ""。每一行邏輯都像藤蔓一樣死死地纏繞在 HTML 標籤上。
「孩子,你這是在 『手動控制每一條肌肉』。每當你想讓勇者揮劍,你都要手動計算肌肉的收縮、骨骼的移動。難怪你累壞了。」
「那我們該怎麼辦?」
「很簡單。你只需要告訴勇者:『目標:史萊姆,動作:揮劍』。至於怎麼收縮肌肉,那是 『自動化生產線』 的事。這,就是 資料驅動 (State-driven)。」
💡 【導師講義:底層真相探究】
在現代開發中,我們將網頁拆解為兩個部分:大腦 (State) 與 投影機 (Render)。
1. 什麼是 State (狀態)?
它是你應用程式唯一的真相來源。它通常是一個簡單的 JS 物件或陣列。
- 範例:
const monsterList = [{ name: '史萊姆', hp: 100 }]; - 原則:大腦只管資料長什麼樣子,完全不理會網頁上有沒有
<div>。
2. 什麼是 Render (渲染)?
它是一台盲目的投影機。它的工作只有一個:讀取大腦的資料,然後噴出對應的 HTML。
- 原則:渲染函式不具備思考能力,你給它什麼資料,它就畫出什麼畫面。
3. 核心心法:單向驅動
當你想改變畫面時,絕對禁止 直接去動 DOM。
- 修改資料 (State):例如將 HP 從 100 改成 80。
- 重新投影 (Render):呼叫渲染函式,它會根據新資料重新畫一遍。
| 特性 | 手動操控 (DOM-driven) | 資料驅動 (State-driven) |
|---|---|---|
| 修改對象 | 直接改 HTML 標籤 | 只改 JS 物件資料 |
| 程式碼長相 | 充滿 querySelector | 充滿 Array 方法 (map/filter) |
| 維護難度 | 極高 (改 A 壞 B) | 低 (資料清純,畫面好修) |
整個流程就像是一場電影放映。你的 State 就是「底片」,Render 函式就是「投影機」。如果你想改變螢幕上的內容,你該做的是換一張底片,而不是跑去螢幕前面塗鴉。

⚔️ 【戰術對抗:學長與學弟的代碼對決】
招式示範:更新血量顯示
❌ 冒險學弟:肌肉勞損法
// 如果血量變了,我要手動抓標籤,然後改顏色,改文字...
function takeDamage(id, amount) {
const hpEl = document.querySelector(`#hp-${id}`);
const newHp = Number(hpEl.textContent) - amount;
hpEl.textContent = newHp;
if (newHp < 20) hpEl.style.color = "red";
}
- 負能量評級:🔴 邏輯與樣式死結 / 🔴 難以擴展
✅ 勇者學長:指揮官心法
// 1. 大腦 (State)
let monsterState = { hp: 100, name: "史萊姆" };
// 2. 投影機 (Render)
function render() {
const container = document.getElementById("app");
// 💡 直接用資料決定畫面內容與樣式
container.innerHTML = `
<div class="monster" style="color: ${monsterState.hp < 20 ? "red" : "black"}">
${monsterState.name} - HP: ${monsterState.hp}
</div>
`;
}
// 3. 修改資料 (State)
function takeDamage(amount) {
monsterState.hp -= amount; // 只改資料
render(); // 重新投影
}
- 利潤評級:🟢 邏輯集中 / 🟢 畫面完全由資料決定
注意看學長的寫法。render 函式完全不知道「血量為什麼會變」,它只知道「現在資料是多少,我就畫什麼」。這就是我們在 Day 25 學過的 SoC (關注點分離) 的極致表現。
🏰 【勇者精英課:邁向職人的進階架構】
你可能會問:「導師,每次資料變了都要重新 innerHTML 整塊畫面,效能不會很差嗎?」
好問題!這就是為什麼我們需要這 30 天修煉的終點 —— 現代前端框架。它們在底層實作了複雜的「差分算法 (Diffing)」,能聰明地只更新有變動的小地方。
但在你拿起聖劍前,你必須先學會「不直接動 DOM」的思維。因為如果你還抱持著「手動抓 ID 改文字」的習慣,那你就永遠無法發揮聖劍的威力。
我曾經在一個大型專案中,因為懶得寫 Render 函式,直接在一個 Ajax 的回呼裡改了 5 個 DOM。結果過了三個月,另一個功能也需要改那 5 個 DOM。
到了最後,我的程式碼裡有 20 個地方在競爭那 5 個 DOM 的主控權。那是我的工程生涯中,離「崩潰」最近的一次。
從那天起,我發誓:除非是極簡單的特效,否則我絕對不再直接操作 DOM。我只改資料。
天色微亮,營火雖已燃盡,但你眼中卻閃爍著領悟的光芒。在前往演武場挑戰關卡前,我已經幫你把靈魂碎片精煉成了這份「戰術錦囊」。拿好它,今日的任務不再是負擔,而是你證明自我的舞台。去吧,公會的英雄榜在等著你的戰報。
📝 【夥伴筆記:今日修煉精華】
這份筆記是你的隨身護身符,卡關時看一眼,真相就在裡面。
- State (狀態):應用的靈魂,唯一的真相。
- Render (渲染):將 State 具現化為 HTML 的純函式。
- 黃金法則:資料驅動 UI (UI = f(state))。資料一變,畫面必變。
🎯 【實戰演武場】
⚔️ 任務鑑定條件:
- 完成 📜 本日實戰任務 (CodePen)。
- 將 CodePen 網址貼至 QuestBoard,並回填鑑定報告:
- 初心者:指揮官啟蒙 (成就感發掘):
-
- 你能成功透過修改
state陣列,讓畫面自動多出一隻史萊姆嗎?
- 你能成功透過修改
-
- 冒險者:戰略大師 (理性挑戰):[⚡ 觀念辨析]
-
- 為什麼說「資料驅動」比起「手動操作 DOM」更適合團隊協作?
-
- 初心者:指揮官啟蒙 (成就感發掘):
📚 【圖書館卷軸與前後站連結】
- 前導冒險: Day 00: 轉職冒險序章
- 上一站冒險: Day 26: 防抖與節流
- 下一站冒險: Day 28: React 與 JS
- MDN 官方參考手冊: DOM - MDN