Fix stale prevRef blocking cross-def change detection
This commit is contained in:
parent
5bea485378
commit
f1447a3b91
@ -156,16 +156,47 @@ export function useFieldValidations<T>(
|
||||
useEffect(() => {
|
||||
const getVal = (name: FormNamePath<T>) => form.getFieldValue(name);
|
||||
|
||||
// ── 静态 def diff ──
|
||||
// ═══ 第一遍:纯检测,不写 prevRef ═══
|
||||
|
||||
// 静态 def
|
||||
const changedStaticDefs: StaticValidationDef<T>[] = [];
|
||||
for (const def of staticDefs) {
|
||||
const defKey = pathKey(def.target);
|
||||
const depKeys = def.deps.map((d) => pathKey(d));
|
||||
let changed = false;
|
||||
for (const dk of [defKey, ...depKeys]) {
|
||||
const cur = JSON.stringify(snapshot[dk]);
|
||||
if (prevRef.current[dk] !== cur) { changed = true; prevRef.current[dk] = cur; }
|
||||
if (prevRef.current[dk] !== JSON.stringify(snapshot[dk])) {
|
||||
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;
|
||||
if (timersRef.current[timerKey]) clearTimeout(timersRef.current[timerKey]);
|
||||
@ -179,53 +210,46 @@ export function useFieldValidations<T>(
|
||||
}, def.debounce ?? 800);
|
||||
}
|
||||
|
||||
// ── 列表 def 逐行 diff ──
|
||||
for (const ld of listDefs) {
|
||||
// 列表 def
|
||||
for (const [ld, changedRows] of changedListRows) {
|
||||
const listKey = pathKey(ld.list);
|
||||
const prevRows = (prevRef.current[listKey] ?? []) as string[];
|
||||
const curRows = (snapshot[listKey] ?? []) as string[];
|
||||
|
||||
// 写入 prevRef
|
||||
prevRef.current[listKey] = curRows;
|
||||
|
||||
if (!isShallowArrEqual(prevRows, curRows)) {
|
||||
// 找出变化的行
|
||||
const maxLen = Math.max(prevRows.length, curRows.length);
|
||||
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);
|
||||
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]);
|
||||
// 清除被删除行的 timer 和 result
|
||||
const prevLen = (prevRef.current[listKey + "_len"] as number | undefined) ?? curRows.length;
|
||||
for (let i = curRows.length; i < prevLen; i++) {
|
||||
const oldTimerKey = timerKey(ld, i);
|
||||
if (timersRef.current[oldTimerKey]) clearTimeout(timersRef.current[oldTimerKey]);
|
||||
const deletedKey = pathKey([...toArray(ld.list), i, ld.target]);
|
||||
setResults((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[deletedKey];
|
||||
return next;
|
||||
});
|
||||
}
|
||||
prevRef.current[listKey + "_len"] = curRows.length;
|
||||
|
||||
// 为变化行重置定时器
|
||||
for (const i of changedRows) {
|
||||
if (i >= curRows.length) continue;
|
||||
const rowTimerKey = timerKey(ld, i);
|
||||
if (timersRef.current[rowTimerKey]) clearTimeout(timersRef.current[rowTimerKey]);
|
||||
timersRef.current[rowTimerKey] = setTimeout(async () => {
|
||||
const getRowVal = (name: string) =>
|
||||
form.getFieldValue([...toArray(ld.list), i, name]);
|
||||
const setRowVal = (name: string, value: unknown) =>
|
||||
form.setFieldValue([...toArray(ld.list), i, name], value);
|
||||
const slot = await ld.validate(getRowVal, i, setRowVal);
|
||||
const rowKey = pathKey([...toArray(ld.list), i, ld.target]);
|
||||
setResults((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[deletedKey];
|
||||
if (slot) next[rowKey] = slot; else delete next[rowKey];
|
||||
return next;
|
||||
});
|
||||
}
|
||||
// 为变化行重置定时器
|
||||
for (const i of changedRows) {
|
||||
if (i >= curRows.length) continue;
|
||||
const rowTimerKey = timerKey(ld, i);
|
||||
if (timersRef.current[rowTimerKey]) clearTimeout(timersRef.current[rowTimerKey]);
|
||||
timersRef.current[rowTimerKey] = setTimeout(async () => {
|
||||
const getRowVal = (name: string) =>
|
||||
form.getFieldValue([...toArray(ld.list), i, name]);
|
||||
const setRowVal = (name: string, value: unknown) =>
|
||||
form.setFieldValue([...toArray(ld.list), i, name], value);
|
||||
const slot = await ld.validate(getRowVal, i, setRowVal);
|
||||
const rowKey = pathKey([...toArray(ld.list), i, ld.target]);
|
||||
setResults((prev) => {
|
||||
const next = { ...prev };
|
||||
if (slot) next[rowKey] = slot; else delete next[rowKey];
|
||||
return next;
|
||||
});
|
||||
}, ld.debounce ?? 800);
|
||||
}
|
||||
}, ld.debounce ?? 800);
|
||||
}
|
||||
}
|
||||
}, [snapshot, staticDefs, listDefs, form]);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user