Skip to content

Commit e5684e8

Browse files
committed
refactor(ui): 拆 NoteListView 第 2 步 — 序行 store hook
1 parent d7921d8 commit e5684e8

2 files changed

Lines changed: 64 additions & 33 deletions

File tree

‎app/src/components/NoteListView.tsx‎

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { emptySelection, rangeSelection, toggleSelection } from "../utils/noteSe
2525
import { dropNotesIntoOrder, shiftNoteOrder } from "../utils/noteOrder";
2626
// 批 0-C2:展示节/可见序纯函数层(含 scope 键与裸折叠键派生——纯逻辑与副作用分离)
2727
import { buildSections, buildVisibleOrder, isTreeMode, manualBaseIds, scopeKey } from "../utils/noteSectionModel";
28+
// 批 0-C2:序行 store(笔记手排序行 + 组手排序行)——兑现既有登记拆分计划
29+
import { useNoteOrders } from "../hooks/useNoteOrders";
2830
import NoteListRow from "./NoteListRow";
2931
import NoteTreeSection from "./NoteTreeSection";
3032
import NoteRowContextMenu from "./NoteRowContextMenu";
@@ -101,10 +103,9 @@ export default function NoteListView({
101103

102104
// 组折叠态
103105
const [groupFolds, setGroupFolds] = useState<Record<string, boolean>>({});
104-
// 手动排序 map(scope → 有序 ids)
105-
const [manualOrders, setManualOrders] = useState<Record<string, number[]>>({});
106-
// REQ-315:组手动序行(group_id → seq;树组头排序消费——组置顶/手排在树面生效)
107-
const [groupOrderRows, setGroupOrderRows] = useState<Map<number, number>>(new Map());
106+
107+
// 序行 store(笔记手排序行 + 组手排序行)——装载/保存路径下沉 hooks/useNoteOrders
108+
const { manualOrders, groupOrderRows, saveOrder, resetOrder } = useNoteOrders(refreshToken);
108109

109110
const visibleIdsRef = useRef<number[]>([]);
110111
// L5:行落点并发锁(防陈旧快照互覆)
@@ -140,35 +141,8 @@ export default function NoteListView({
140141
return () => window.removeEventListener("keydown", onKey);
141142
}, [batchMenu, contextMenu, selectionMode, selection.size, exitBatch]);
142143

143-
// 手动序装载(REQ-287:notes 行)+ REQ-315:组序行(树组头排序)。
144-
// Why 依赖 refreshToken:侧栏上移/下移/回自动/手排↺(useGroupOrders→onChanged→
145-
// NotesPage refreshToken++)只经父层令牌通知——挂载单拉会在树面残留旧组序/
146-
// 复位后残留已删序行(审查 P2-10);与父层 refreshAll 同频重载,零去抖必要
147-
// (重载=读操作,量级毫秒级;本组件自持的保存路径 saveOrder 仍内联 loadOrders)
148-
const loadOrders = useCallback(() => {
149-
invoke<[string, number, number][]>("note_order_list")
150-
.then((rows) => {
151-
const map: Record<string, number[]> = {};
152-
for (const [scope, id] of rows) {
153-
(map[scope] ??= []).push(id);
154-
}
155-
setManualOrders(map);
156-
})
157-
.catch((e) => console.warn("[notes] 手动排序读取失败(自动排序兜底):", e));
158-
invoke<[number, number][]>("note_group_order_list")
159-
.then((rows) => setGroupOrderRows(new Map(rows.map(([gid, seq]) => [gid, seq]))))
160-
.catch((e) => console.warn("[notes] 组排序读取失败(自动排序兜底):", e));
161-
}, []);
162-
useEffect(() => { loadOrders(); }, [loadOrders, refreshToken]);
163-
164-
const saveOrder = useCallback(async (scope: string, ids: number[]) => {
165-
await invoke("note_order_save", { scope, noteIds: ids });
166-
loadOrders();
167-
}, [loadOrders]);
168-
const resetOrder = useCallback(async (scope: string) => {
169-
await invoke("note_order_clear", { scope });
170-
loadOrders();
171-
}, [loadOrders]);
144+
// 手动序装载(REQ-287:notes 行)+ REQ-315:组序行(树组头排序)——见 hooks/useNoteOrders
145+
// (依赖 refreshToken 的理由随实现搬至该 hook 头注释:审查 P2-10 的令牌重拉)
172146

173147
// ── 分组树数据(同 v0.15 结构)——可见序统一从本结构生成 ──
174148
// Why 不再有分桶 memo:旧 `grouped` 是死载荷——仅被当作 treeMode 的第二真值,

‎app/src/hooks/useNoteOrders.ts‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* useNoteOrders — 笔记/组「手动序行」store(批 0-C2·Task 2 自 NoteListView 抽出)。
3+
*
4+
* @ai-context: 兑现 line-limit-exemptions 对 NoteListView 的既有拆分计划
5+
* (「拖拽/移动接线拆至 useNoteOrders.ts」)——本文件承载**序行装载与保存
6+
* 路径**(note_order_list / note_order_save / note_order_clear +
7+
* note_group_order_list);移动/拖拽接线在同批的 hooks/useNoteMoves.ts。
8+
* @ai-context: 副作用——挂载与 refreshToken 变化各拉一次;Why 依赖 refreshToken:
9+
* 侧栏上移/下移/回自动/手排↺(useGroupOrders→onChanged→NotesPage
10+
* refreshToken++)只经父层令牌通知——挂载单拉会在树面残留旧组序/复位后
11+
* 残留已删序行(审查 P2-10);与父层 refreshAll 同频重载,零去抖必要。
12+
* save/reset 内联回拉(读操作,量级毫秒级)。读失败 console.warn 兜底
13+
* (自动排序 fallback),不阻断 UI、不吞异常。
14+
* @ai-context: 边界——saveOrder/resetOrder 是**整表覆写**语义;scope 字面量由调用方以
15+
* noteSectionModel.scopeKey 产出(`none` / `g:{id}`,与 Rust 侧契约绑定)。
16+
*/
17+
import { useCallback, useEffect, useState } from "react";
18+
import { invoke } from "@tauri-apps/api/core";
19+
20+
export function useNoteOrders(refreshToken: number) {
21+
// 手动排序 map(scope → 有序 ids)
22+
const [manualOrders, setManualOrders] = useState<Record<string, number[]>>({});
23+
// REQ-315:组手动序行(group_id → seq;树组头排序消费——组置顶/手排在树面生效)
24+
const [groupOrderRows, setGroupOrderRows] = useState<Map<number, number>>(new Map());
25+
26+
// 手动序装载(REQ-287:notes 行)+ REQ-315:组序行(树组头排序)。
27+
// Why 依赖 refreshToken:侧栏上移/下移/回自动/手排↺(useGroupOrders→onChanged→
28+
// NotesPage refreshToken++)只经父层令牌通知——挂载单拉会在树面残留旧组序/
29+
// 复位后残留已删序行(审查 P2-10);与父层 refreshAll 同频重载,零去抖必要
30+
// (重载=读操作,量级毫秒级;自持的保存路径 saveOrder 仍内联 loadOrders)
31+
const loadOrders = useCallback(() => {
32+
invoke<[string, number, number][]>("note_order_list")
33+
.then((rows) => {
34+
const map: Record<string, number[]> = {};
35+
for (const [scope, id] of rows) {
36+
(map[scope] ??= []).push(id);
37+
}
38+
setManualOrders(map);
39+
})
40+
.catch((e) => console.warn("[notes] 手动排序读取失败(自动排序兜底):", e));
41+
invoke<[number, number][]>("note_group_order_list")
42+
.then((rows) => setGroupOrderRows(new Map(rows.map(([gid, seq]) => [gid, seq]))))
43+
.catch((e) => console.warn("[notes] 组排序读取失败(自动排序兜底):", e));
44+
}, []);
45+
useEffect(() => { loadOrders(); }, [loadOrders, refreshToken]);
46+
47+
const saveOrder = useCallback(async (scope: string, ids: number[]) => {
48+
await invoke("note_order_save", { scope, noteIds: ids });
49+
loadOrders();
50+
}, [loadOrders]);
51+
const resetOrder = useCallback(async (scope: string) => {
52+
await invoke("note_order_clear", { scope });
53+
loadOrders();
54+
}, [loadOrders]);
55+
56+
return { manualOrders, groupOrderRows, saveOrder, resetOrder };
57+
}

0 commit comments

Comments
 (0)