~/VibeHandbook
免费 PDF

11 · 03

一个实战示例:"收藏"功能

我们来端到端地做一个小功能:用户可以把列表里的条目标记为收藏,并看到自己收藏了多少个的计数。

切分它

我会这样把它拆成纵向步骤:

  1. 在每个条目旁边加一个星标按钮(暂时什么都不做,只是显示出来)。
  2. 点击星标切换它的亮/灭外观(仅状态,不保存)。
  3. 显示一个反映这些切换的"★ 3 favorites"计数器。
  4. 保存收藏,让它在页面重新加载后依然存在。

注意每一步都可独立运行、可见。你在其中任何一步之后停下,都仍然拥有一个可运行的应用。

第 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.)│      所以它能挺过重载
                         └──────────┘

想离线阅读?

免费下载整本书的 PDF 或 EPUB。