Fix stale prevRef blocking cross-def change detection

This commit is contained in:
CPTProgrammer 2026-07-15 13:05:46 +08:00
parent 5bea485378
commit f1447a3b91
No known key found for this signature in database

View File

@ -156,16 +156,47 @@ export function useFieldValidations<T>(
useEffect(() => { useEffect(() => {
const getVal = (name: FormNamePath<T>) => form.getFieldValue(name); const getVal = (name: FormNamePath<T>) => form.getFieldValue(name);
// ── 静态 def diff ── // ═══ 第一遍:纯检测,不写 prevRef ═══
// 静态 def
const changedStaticDefs: StaticValidationDef<T>[] = [];
for (const def of staticDefs) { for (const def of staticDefs) {
const defKey = pathKey(def.target); const defKey = pathKey(def.target);
const depKeys = def.deps.map((d) => pathKey(d)); const depKeys = def.deps.map((d) => pathKey(d));
let changed = false;
for (const dk of [defKey, ...depKeys]) { for (const dk of [defKey, ...depKeys]) {
const cur = JSON.stringify(snapshot[dk]); if (prevRef.current[dk] !== JSON.stringify(snapshot[dk])) {
if (prevRef.current[dk] !== cur) { changed = true; prevRef.current[dk] = cur; } changedStaticDefs.push(def);
break;
}
}
}
// 列表 def —— 收集每行变化
const changedListRows = new Map<_ListValidationDef<T>, Set<number>>();
for (const ld of listDefs) {
const listKey = pathKey(ld.list);
const prevRows = (prevRef.current[listKey] ?? []) as string[];
const curRows = (snapshot[listKey] ?? []) as string[];
if (isShallowArrEqual(prevRows, curRows)) continue;
const rows = new Set<number>();
const maxLen = Math.max(prevRows.length, curRows.length);
for (let i = 0; i < maxLen; i++) {
if (prevRows[i] !== curRows[i]) rows.add(i);
}
changedListRows.set(ld, rows);
}
// ═══ 第二遍:写入 prevRef + 重置 timer ═══
// 静态 def
for (const def of changedStaticDefs) {
const defKey = pathKey(def.target);
const depKeys = def.deps.map((d) => pathKey(d));
for (const dk of [defKey, ...depKeys]) {
prevRef.current[dk] = JSON.stringify(snapshot[dk]);
} }
if (!changed) continue;
const timerKey = "s_" + defKey; const timerKey = "s_" + defKey;
if (timersRef.current[timerKey]) clearTimeout(timersRef.current[timerKey]); if (timersRef.current[timerKey]) clearTimeout(timersRef.current[timerKey]);
@ -179,27 +210,19 @@ export function useFieldValidations<T>(
}, def.debounce ?? 800); }, def.debounce ?? 800);
} }
// ── 列表 def 逐行 diff ── // 列表 def
for (const ld of listDefs) { for (const [ld, changedRows] of changedListRows) {
const listKey = pathKey(ld.list); const listKey = pathKey(ld.list);
const prevRows = (prevRef.current[listKey] ?? []) as string[];
const curRows = (snapshot[listKey] ?? []) as string[]; const curRows = (snapshot[listKey] ?? []) as string[];
// 写入 prevRef
prevRef.current[listKey] = curRows; prevRef.current[listKey] = curRows;
if (!isShallowArrEqual(prevRows, curRows)) { // 清除被删除行的 timer 和 result
// 找出变化的行 const prevLen = (prevRef.current[listKey + "_len"] as number | undefined) ?? curRows.length;
const maxLen = Math.max(prevRows.length, curRows.length); for (let i = curRows.length; i < prevLen; i++) {
const changedRows = new Set<number>();
for (let i = 0; i < maxLen; i++) {
if (prevRows[i] !== curRows[i]) changedRows.add(i);
}
// 清除多余旧行的 timer
for (let i = curRows.length; i < prevRows.length; i++) {
const oldTimerKey = timerKey(ld, i); const oldTimerKey = timerKey(ld, i);
if (timersRef.current[oldTimerKey]) clearTimeout(timersRef.current[oldTimerKey]); if (timersRef.current[oldTimerKey]) clearTimeout(timersRef.current[oldTimerKey]);
}
// 清除已删除行的 result
for (let i = curRows.length; i < prevRows.length; i++) {
const deletedKey = pathKey([...toArray(ld.list), i, ld.target]); const deletedKey = pathKey([...toArray(ld.list), i, ld.target]);
setResults((prev) => { setResults((prev) => {
const next = { ...prev }; const next = { ...prev };
@ -207,6 +230,8 @@ export function useFieldValidations<T>(
return next; return next;
}); });
} }
prevRef.current[listKey + "_len"] = curRows.length;
// 为变化行重置定时器 // 为变化行重置定时器
for (const i of changedRows) { for (const i of changedRows) {
if (i >= curRows.length) continue; if (i >= curRows.length) continue;
@ -227,7 +252,6 @@ export function useFieldValidations<T>(
}, ld.debounce ?? 800); }, ld.debounce ?? 800);
} }
} }
}
}, [snapshot, staticDefs, listDefs, form]); }, [snapshot, staticDefs, listDefs, form]);
// 卸载时清除所有定时器 // 卸载时清除所有定时器