diff --git a/src/hooks/useFieldValidations.tsx b/src/hooks/useFieldValidations.tsx index 670e484..978bb88 100644 --- a/src/hooks/useFieldValidations.tsx +++ b/src/hooks/useFieldValidations.tsx @@ -156,16 +156,47 @@ export function useFieldValidations( useEffect(() => { const getVal = (name: FormNamePath) => form.getFieldValue(name); - // ── 静态 def diff ── + // ═══ 第一遍:纯检测,不写 prevRef ═══ + + // 静态 def + const changedStaticDefs: StaticValidationDef[] = []; 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, Set>(); + 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(); + 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( }, 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(); - 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]);