一個實戰示例:"收藏"功能
我們來端到端地做一個小功能:使用者可以把列表裡的條目標記為收藏,並看到自己收藏了多少個的計數。
切分它
我會這樣把它拆成縱向步驟:
- 在每個條目旁邊加一個星標按鈕(暫時什麼都不做,只是顯示出來)。
- 點選星標切換它的亮/滅外觀(僅狀態,不儲存)。
- 顯示一個反映這些切換的"★ 3 favorites"計數器。
- 儲存收藏,讓它在頁面重新載入後依然存在。
注意每一步都可獨立執行、可見。你在其中任何一步之後停下,都仍然擁有一個可執行的應用。
第 1 步:按鈕
一條好的提示會點明檔案、改動,以及不要碰什麼:
在 ItemCard 元件(src/components/ItemCard.jsx)中,給每張卡片的
右上角加一個星標按鈕。它應該渲染一個輪廓星標圖示。先別接上任何
點選行為——只讓它顯示出來。保持卡片其餘的佈局不變。
執行應用。看到星標了嗎?好。提交:
git add -A && git commit -m "Add star button to item cards"
第 2 步:切換狀態
讓星標按鈕在被點選時在填充和輪廓之間切換。用本地元件狀態來追蹤
它——先別儲存到任何地方。填充的星標表示已收藏。
可以把狀態(state)想成應用的短期記憶——此刻什麼是真的,比如某顆星星現在是否處於填充狀態。現在你在同時處理狀態和 UI,這很正常。(UI,即使用者介面,就是應用中人能看到、能點選的那一部分。)AI 大概會加上類似這樣的東西:
const [isFavorite, setIsFavorite] = useState(false);
<button onClick={() => setIsFavorite(!isFavorite)}>
{isFavorite ? <StarFilled /> : <StarOutline />}
</button>
點幾下星標。它們會切換嗎?提交。
第 3 步:計數器
在條目列表頂部加一個"★ N favorites"計數器。它應該統計當前有多少
個條目的星標被填充。如果需要,把收藏狀態上提到列表元件,好讓
計數器能看到它。
這一步可能要求 AI 重構狀態所在之處——這在預料之中,而這恰恰是為什麼你要把它作為獨立的小步驟來做。執行它,切換幾個星標,看著數字變化。提交。
第 4 步:讓它持久化
把收藏持久化,讓它們能挺過頁面過載。現在先用 localStorage——每當
收藏條目 ID 的列表變化時就儲存它,並在啟動時載入它。
(localStorage 就是瀏覽器在訪客自己電腦上保留的一個小記事本,應用可以把東西記下來,重新載入之後再找回來。)重新載入頁面。還是收藏狀態嗎?你剛剛交付了一個功能,一次一個可執行的切片。
來看看這個完成的功能裡各部件是怎麼互相對話的。一次點擊向下流入狀態,螢幕從狀態重繪,而狀態被映象到儲存裡,於是它在重新載入後依然存活:
┌─────────────────────────────────────────────┐
│ │
點選星標 從狀態
│ (事件) 重繪
▼ ▲
┌────────┐ 更新 ┌─────────┐ 饋送 ┌────────┐
│ UI │─────────────▶│ 狀態 │───────────▶│ UI │
│ (按鈕) │ │(應用內 │ │(填充的 │
└────────┘ │ 記憶體) │ │ 星標 + │
└────┬────┘ │計數器) │
│ 變更時儲存 └────────┘
▼
┌──────────┐
│ 儲存 │ ◀── 啟動時載入,
│(localSt.)│ 所以它能挺過過載
└──────────┘