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(() => {
|
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,53 +210,46 @@ 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>();
|
const oldTimerKey = timerKey(ld, i);
|
||||||
for (let i = 0; i < maxLen; i++) {
|
if (timersRef.current[oldTimerKey]) clearTimeout(timersRef.current[oldTimerKey]);
|
||||||
if (prevRows[i] !== curRows[i]) changedRows.add(i);
|
const deletedKey = pathKey([...toArray(ld.list), i, ld.target]);
|
||||||
}
|
setResults((prev) => {
|
||||||
// 清除多余旧行的 timer
|
const next = { ...prev };
|
||||||
for (let i = curRows.length; i < prevRows.length; i++) {
|
delete next[deletedKey];
|
||||||
const oldTimerKey = timerKey(ld, i);
|
return next;
|
||||||
if (timersRef.current[oldTimerKey]) clearTimeout(timersRef.current[oldTimerKey]);
|
});
|
||||||
}
|
}
|
||||||
// 清除已删除行的 result
|
prevRef.current[listKey + "_len"] = curRows.length;
|
||||||
for (let i = curRows.length; i < prevRows.length; i++) {
|
|
||||||
const deletedKey = pathKey([...toArray(ld.list), i, ld.target]);
|
// 为变化行重置定时器
|
||||||
|
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) => {
|
setResults((prev) => {
|
||||||
const next = { ...prev };
|
const next = { ...prev };
|
||||||
delete next[deletedKey];
|
if (slot) next[rowKey] = slot; else delete next[rowKey];
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
}
|
}, ld.debounce ?? 800);
|
||||||
// 为变化行重置定时器
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [snapshot, staticDefs, listDefs, form]);
|
}, [snapshot, staticDefs, listDefs, form]);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user