fix: 知识图谱与思维导图不显示内容

三个独立 bug 修复:
1. MindmapTree StrictMode 双重渲染: Effect 1 创建 mm 实例, Effect 2 设置数据,
   StrictMode 下 Effect 1 重建 mm 但 Effect 2 不重新运行 → 新 mm 无数据
   修复: 在 Effect 1 中用 useStore.getState().tree 设置初始数据

2. LinkGraph onSwitchToEditor 不稳定: App 传内联箭头函数每次渲染新引用,
   导致 D3 力导向图 Effect 2 依赖变化不断重置 → 图谱闪烁/不显示
   修复: useCallback 稳定 switchToEditor 引用

3. frontmatter 块式 YAML 列表解析: parseList 只支持内联 [a, b] 格式,
   用户手写 links:/tags: 多行 - item 格式无法解析 → 知识图谱无边
   修复: parseYaml 支持 YAML 块式列表 (- item 多行)

新增 E2E 测试 graph-render.spec.ts 验证思维导图+知识图谱渲染内容
新增单元测试覆盖块式 YAML 列表解析
This commit is contained in:
hunter-dev
2026-08-27 16:35:47 +08:00
parent ebd955ce4b
commit 96f5c72fa7
5 changed files with 105 additions and 5 deletions
+3 -2
View File
@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useCallback } from 'react';
import { useStore } from './store';
import { invoke } from './ipc-client';
import { IPC } from '@hunter/shared';
@@ -41,6 +41,7 @@ export function App() {
const appearance = useAppearance();
const settings = useSettings();
const layout = useLayout();
const switchToEditor = useCallback(() => setView('editor'), []);
useEffect(() => { loadVault(); loadTree(); restore(); appearance.load(); useKeymap.getState().load(); useSettings.getState().loadGpu(); }, []);
useEffect(() => { if (activeId && tabs.length > 0) { const t = tabs.find(x => x.id === activeId); if (t) openDoc(t.path).then(() => {
@@ -93,7 +94,7 @@ export function App() {
</div>
<Resizer side="left" onDrag={d => layout.setSidebarWidth(layout.sidebarWidth + d)} />
</>)}
{view === 'editor' ? <Editor /> : <GraphView onSwitchToEditor={() => setView('editor')} />}
{view === 'editor' ? <Editor /> : <GraphView onSwitchToEditor={switchToEditor} />}
{view === 'editor' && layout.outlineVisible && (<>
<Resizer side="right" onDrag={d => layout.setOutlineWidth(layout.outlineWidth + d)} />
<div style={{ width: layout.outlineWidth, borderLeft: '1px solid var(--control-border)', display: 'flex', flexDirection: 'column', overflow: 'hidden', flexShrink: 0 }}>
@@ -61,6 +61,12 @@ function MindmapTree() {
if (!svg) return;
const mm = new Markmap(svg, MARKMAP_OPTIONS);
mmRef.current = mm;
// 初始数据:StrictMode 双重渲染或视图切换时 Effect 2 不会重新运行,
// 这里直接读 store 当前 tree 设置初始数据,确保 mm 实例有内容
const curTree = useStore.getState().tree;
if (curTree.length > 0) {
mm.setData(toMarkmapTree(curTree) as never).catch(() => {});
}
const onClick = (e: MouseEvent) => {
const target = e.target as Element | null;
if (!target) return;