diff --git a/docs/superpowers/plans/2026-06-25-blog-writing.md b/docs/superpowers/plans/2026-06-25-blog-writing.md index 75cadb5..0f589e6 100644 --- a/docs/superpowers/plans/2026-06-25-blog-writing.md +++ b/docs/superpowers/plans/2026-06-25-blog-writing.md @@ -1258,6 +1258,9 @@ export function BlogPage({ username, token, initialPostId, onSignOut }: BlogPage // 编辑器浮层:editing=true 时无视路由优先显示编辑器;editingPost=null 为新建。 const [editing, setEditing] = useState(false) const [editingPost, setEditingPost] = useState(null) + // 文章重挂载计数:保存编辑后 bump,作为 PostArticle 的 key 强制重拉 + // (否则 id 不变时其 useEffect 不会重新 fetch,显示旧内容)。 + const [articleNonce, setArticleNonce] = useState(0) const refresh = useCallback(() => { setLoading(true) @@ -1288,9 +1291,11 @@ export function BlogPage({ username, token, initialPostId, onSignOut }: BlogPage setEditing(true) } const onEditorSaved = () => { - // 编辑既有文章:hash 仍是 #post/,关掉编辑器即回到该文章(会重拉)。 + // 编辑既有文章:hash 仍是 #post/,关掉编辑器即回到该文章;bump + // articleNonce 让 PostArticle 重挂载、重拉到最新内容。 // 新建:hash 为空,关掉后回列表。两种都刷新列表数据。 setEditing(false) + setArticleNonce((n) => n + 1) refresh() } @@ -1309,6 +1314,7 @@ export function BlogPage({ username, token, initialPostId, onSignOut }: BlogPage } else if (initialPostId) { center = ( " - **Spec coverage**:存储/上限/接口/鉴权(Task 1-2);api 封装 + 派生(Task 3);Markdown(Task 4);编辑器(Task 5);阅读页(Task 6);列表改造 + `#post/` 路由 + 边界态(Task 7)。spec 各节均有对应任务。 - **路由真相源**:列表↔文章统一由 `App.tsx` 经 hash 决定(`initialPostId`),`BlogPage` 仅管编辑器浮层,避免双方争用 URL。编辑器不进 URL(不可分享,符合 spec)。 - **类型一致**:`Post`/`PostInput`/`PostError` 在 Task 3 定义,Task 5/6/7 一致引用;后端 `Post` camelCase 与前端字段对齐。 +- **就地编辑刷新**:`PostArticle` 的 fetch effect 依赖 `[token, id]`,id 不变时不会重拉;故编辑保存后 bump `articleNonce` 并用作 `key` 强制重挂载,保证文章页显示最新内容(Task 7)。 +- **Markdown code 边界**:以 `language-` 类名区分行内/块级,未指定语言的 ```围栏块``` 会被当作行内样式——个人博客可接受(写 ```lang 即可),不为此引 `node` 判定增复杂度。 - **已知取舍**:返回列表用 `window.location.hash = ''` 会留下一个光秃秃的 `#`(cosmetic),换页/刷新无副作用;如介意可在 `backToList` 改用 `history.pushState` + 手动置空 `initialPostId`,但那会让 BlogPage 也参与路由、复杂度上升,故不采用。 ```