Skip to content

第一章练习答案 ​

搜索词、分类和排序适合放进 URL,因为它们需要刷新后恢复并可分享;结果列表、请求状态和错误属于服务端状态;“过滤后有多少条”是派生值,不应单独存储。组件临时打开的筛选面板属于本地 UI 状态。

哪些状态可以保存 ​

持久化只保存可恢复的用户偏好,不保存 access token。下面的纯函数把版本迁移、损坏 JSON 和未知字段分开处理:

js
export function restoreSettings(raw) {
  if (raw == null) return { version: 2, theme: 'system', density: 'comfortable' }
  try {
    const value = JSON.parse(raw)
    if (value.version === 1) {
      return { version: 2, theme: value.dark ? 'dark' : 'light', density: 'comfortable' }
    }
    if (value.version !== 2) throw new Error('unsupported version')
    if (!['light', 'dark', 'system'].includes(value.theme)) throw new Error('invalid theme')
    if (!['compact', 'comfortable'].includes(value.density)) throw new Error('invalid density')
    return { version: 2, theme: value.theme, density: value.density }
  } catch {
    return { version: 2, theme: 'system', density: 'comfortable' }
  }
}

console.assert(restoreSettings('{"version":1,"dark":true}').theme === 'dark')
console.assert(restoreSettings('{"version":2,"theme":"bad"}').theme === 'system')

测试还要验证登出时删除用户前缀 key,以及切换用户后 query key 包含新的 userId;这两条不是“清空一个全局对象”可以替代的。

先决定谁拥有状态 ​

状态 owner 的判断结果是:输入草稿归表单组件,已提交筛选归 URL,远程列表归 query cache,未提交的派生计数不单独存储。若把 filteredItems 再保存一份,修改筛选后必须同步两份状态,正是练习要求发现的冗余来源。

只接受仍然有效的结果 ​

竞态题的参考断言是“只接受最后一次请求”:为每次请求分配递增 requestId,响应提交前比较它与当前 id;旧响应即使成功也只能被记录为 discarded,不能覆盖 UI。取消请求减少资源消耗,但不能代替提交前的身份判断。

缓存不是全局真相 ​

缓存题必须区分 query identity、freshness 和 UI 状态。改变 userId 或筛选参数时应生成新 key;mutation 成功后失效相关 key,失败则保留旧数据并呈现可重试错误,不能用全局 loading 覆盖不同请求的生命周期。

用心记录每一步成长