上一篇的備忘錄裡,我們把資料先放進一個 Array:
const memos = [];
memos.push("買牛奶");
這時候:
memos
// ["買牛奶"]
畫面上也可以正常顯示「買牛奶」。
但只要重新整理頁面,資料就不見了。
原因其實很簡單:
畫面上看得到資料,不代表資料已經被長期保存。
這也是我後來 Debug 時很常先確認的一件事:
這份資料真正住在哪裡?
像這樣:
const memos = [];
資料目前只是存在 JavaScript 執行期間。
流程可以簡單理解成:
載入頁面
↓
建立 memos = []
↓
加入「買牛奶」
↓
memos = ["買牛奶"]
↓
重新整理頁面
↓
JavaScript 重新執行
↓
重新建立 memos = []
所以重新整理之後資料消失,不是因為瀏覽器把它刪掉了。
而是程式重新從頭執行,我們又建立了一個新的空 Array。
如果希望重新整理之後資料仍然存在,可以把資料另外存進瀏覽器。
例如 localStorage:
const memos = ["買牛奶", "寫鐵人賽"];
localStorage.setItem("memos", JSON.stringify(memos));
重新載入頁面時,再取回來:
const savedMemos = localStorage.getItem("memos");
const memos = savedMemos
? JSON.parse(savedMemos)
: [];
這裡可以先記住:
JavaScript Array
↓
JSON.stringify()
↓
localStorage
取出時則反過來:
localStorage
↓
JSON.parse()
↓
JavaScript Array
另外也常看到 sessionStorage。
最簡單可以先這樣區分:
| 儲存位置 | Reload | 關閉分頁後 |
|---|---|---|
| JavaScript 變數 | 消失 | 消失 |
sessionStorage |
通常還在 | 通常消失 |
localStorage |
還在 | 還在 |
但不論 localStorage 或 sessionStorage,資料都還是存在目前使用者的瀏覽器端。
如果今天不是練習用備忘錄,而是一個真正有帳號、多人使用的系統,就不能只依賴某一台電腦的 localStorage。
新增資料時可能會變成:
使用者輸入資料
↓
Frontend
↓
POST / API
↓
Backend
↓
Database
重新整理頁面時:
頁面載入
↓
GET / API
↓
Backend
↓
Database
↓
Response
↓
Frontend
↓
重新顯示畫面
所以「重新整理後資料還在」可能有很多原因。
它可能來自:
localStorage
也可能是:
重新呼叫 API
↓
Backend 從 Database 取回資料
光看畫面,不一定能直接知道資料來源。
後來在實際專案裡,我曾經遇過一類很典型的狀況。
使用者修改某個表單欄位,按下儲存。
從 Network 看起來:
PATCH Request
↓
Status 200
↓
Request 裡也確實帶了新的值
乍看之下,好像更新成功了。
但重新取得資料後:
GET / API
↓
Response
↓
原本的舊值又回來
最後畫面也跟著恢復原本的內容。
如果只盯著 UI,很容易一直往 Input、Form 或 Render 的方向修改。
但把流程拆開之後:
使用者修改
↓
Frontend Form
↓
PATCH Request
↓
Backend
↓
Database
↓
Response
↓
Frontend Render
就可以逐層確認:
這時候有一個很重要的觀念:
HTTP 200 不代表資料一定已經變成你期待的樣子。
200 代表這次 Request 成功被處理。
但真正 Debug 時,還需要繼續確認:
資料最後到底有沒有被正確保存。
這也是我後來很常提醒自己的地方。
UI 顯示
↓
Frontend State / Variable
↓
Request
↓
Backend
↓
Database
↓
Response
↓
重新 Render
其中任何一層出問題,使用者最後看到的結果都可能不一樣。
例如只做:
li.remove();
代表的是:
把畫面上的元素移除。
但如果真正的資料還存在 Database,
下一次重新呼叫 API:
Database
↓
Response
↓
Frontend
那筆資料還是會重新出現。
所以:
畫面消失,不代表資料真的被刪除了。
同樣地:
畫面顯示新值,也不代表 Database 一定已經更新。
遇到資料顯示異常時,我通常會先確認:
這個值現在看到的是哪一層?
↓
是 Form 裡的值?
↓
是 State?
↓
是 API Response?
↓
還是 Database 回來的資料?
再繼續追:
Request 送了什麼?
↓
Response 回了什麼?
↓
最後畫面又使用哪份資料 Render?
對我來說,這比單純看到:
200 OK
就判斷「API 沒問題」,可靠很多。
UI
│
▼
Frontend Data
│
├─ JavaScript Variable
│ └─ Reload 後重新建立
│
├─ localStorage / sessionStorage
│ └─ 儲存在瀏覽器
│
└─ API
↓
Backend
↓
Database
所以看到一筆資料時,可以多問一句:
它真正的 Source of Truth 在哪裡?
這個問題之後到了 React、表單、API Debug,還會一直出現。
下一篇可以繼續把同一個備忘錄往 React 移動:
同樣是新增資料,為什麼到了 React 會開始出現 useState、onClick 和重新 Render?