fix(post): 上下篇切换后可运行代码块消失
承接前两轮修复:路由重跑(79978aa)、正文更新(f86cb48)后,翻页时文章正文
正确切换了,但可运行代码块(CodeRunner)消失——容器 div 还在,CodeMirror
编辑器没挂载。
根因:上下篇切换(/post/rust → /post/go)时 PostContent 组件被复用(仅重渲染,
非重新挂载)。其内部 CodeRunner 用片段索引作 key(runner-{i}),而两篇文章的
代码块索引恰好相同(都是 1/3/5),keyed diff 按相同 key 复用 CodeRunner 实例。
复用的实例保留 use_hook/use_effect 状态:挂载 use_effect 的「防重复 init」守卫
(editor_handle.is_some())阻止 CodeMirror 挂载到新的(已替换的)DOM 容器,
而旧 CodeMirror 还绑定在被销毁的 rust DOM 上。同时 PostContent 自身的 use_effect
(__initPostContent 复制按钮 / 灯箱初始化)也不重跑,新文章交互脚本不初始化。
曾尝试直接给 PostContent 加 key=post.slug,无效:Dioxus 的 key diff
(diff_keyed_children)只在「兄弟节点列表」里生效,对单个非列表元素的 key
变化走 diff_non_keyed 路径、按位置复用,不触发 remount(经 use_hook 探针确认:
翻页后 CodeRunner 函数体执行了但 use_hook 从未重新执行)。
修复:把 PostContent 包进单元素 keyed 列表(for + iter::once + key=slug),
使其进入 keyed diff 路径——slug 变化时旧实例移除、新实例创建,连带 CodeRunner
重新挂载、交互脚本重新初始化。
验证(headless chromium,rust↔go 各含3个代码块):
- 修复前:翻页后容器在、CodeMirror 挂载数=0(红灯)
- 修复后:CodeMirror 挂载数=3,骨架屏清零;prev/next 双向 + SSR 首屏均正常
This commit is contained in:
parent
2498cd9c0b
commit
b5a64f8dcf
@ -78,7 +78,27 @@ pub fn PostDetail(slug: String) -> Element {
|
||||
PostToc { toc_html: toc.clone() }
|
||||
}
|
||||
|
||||
PostContent { content_html: post.content_html.clone().unwrap_or_default() }
|
||||
// 用单元素 keyed 列表包裹 PostContent,key 绑定 slug。
|
||||
//
|
||||
// 为什么不能直接给 PostContent 加 key:Dioxus 的 key diff(diff_keyed_children)
|
||||
// 只在「兄弟节点列表」里生效,对单个非列表元素的 key 变化会走 diff_non_keyed
|
||||
// 路径、按位置复用,不触发 remount。把组件放进单元素 for 循环并带 key,
|
||||
// 才会进入 keyed diff——slug 变化时旧 PostContent 被移除、新的被创建。
|
||||
//
|
||||
// 为什么需要 remount:上下篇切换时 PostContent 若被复用(仅重渲染),
|
||||
// (1) 内部 CodeRunner 用片段索引作 key,两篇文章索引可能相同(如 1/3/5),
|
||||
// keyed diff 按相同 key 复用 CodeRunner 实例——其挂载 use_effect 的
|
||||
// 「防重复 init」守卫阻止 CodeMirror 挂载到新的(已替换的)DOM 容器,
|
||||
// 表现为翻页后代码块消失;
|
||||
// (2) PostContent 自身的 use_effect(__initPostContent 复制按钮 / 灯箱初始化)
|
||||
// 也不会重跑,新文章的交互脚本不初始化。
|
||||
// 强制 remount 让编辑器与脚本随文章切换全部重新初始化。
|
||||
for post_slug in std::iter::once(post.slug.clone()) {
|
||||
PostContent {
|
||||
key: "{post_slug}",
|
||||
content_html: post.content_html.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
PostFooter { post: post.clone() }
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user