73 lines
1.9 KiB
TypeScript
73 lines
1.9 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import React from 'react';
|
||
|
|
import { useFormContext } from './context';
|
||
|
|
import type { FormErrorProps } from './types';
|
||
|
|
|
||
|
|
export const FormError = <
|
||
|
|
TValues extends Record<string, any> = Record<string, any>,
|
||
|
|
>(
|
||
|
|
props: FormErrorProps<TValues>
|
||
|
|
) => {
|
||
|
|
const { name, render } = props;
|
||
|
|
const { getFieldError, subscribe } = useFormContext<TValues>();
|
||
|
|
|
||
|
|
// 使用 useState 管理字段错误状态
|
||
|
|
const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>(
|
||
|
|
() => {
|
||
|
|
const errors: Record<string, string> = {};
|
||
|
|
name.forEach((fieldName) => {
|
||
|
|
const error = getFieldError(fieldName);
|
||
|
|
if (error) {
|
||
|
|
errors[fieldName] = error;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return errors;
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
// 使用 useEffect 订阅字段错误的变化
|
||
|
|
React.useEffect(() => {
|
||
|
|
const unsubscribes = name.map((fieldName) =>
|
||
|
|
subscribe(fieldName, () => {
|
||
|
|
// 当字段错误变化时,更新状态
|
||
|
|
setFieldErrors((prev) => {
|
||
|
|
const newErrors: Record<string, string> = { ...prev };
|
||
|
|
let hasChanged = false;
|
||
|
|
|
||
|
|
name.forEach((field) => {
|
||
|
|
const error = getFieldError(field);
|
||
|
|
if (error) {
|
||
|
|
if (newErrors[field] !== error) {
|
||
|
|
newErrors[field] = error;
|
||
|
|
hasChanged = true;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (field in newErrors) {
|
||
|
|
delete newErrors[field];
|
||
|
|
hasChanged = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return hasChanged ? newErrors : prev;
|
||
|
|
});
|
||
|
|
})
|
||
|
|
);
|
||
|
|
|
||
|
|
return () => {
|
||
|
|
unsubscribes.forEach((unsub) => unsub());
|
||
|
|
};
|
||
|
|
}, [name, subscribe, getFieldError]);
|
||
|
|
|
||
|
|
// 检查是否有错误
|
||
|
|
const hasError = Object.keys(fieldErrors).length > 0;
|
||
|
|
|
||
|
|
// 只有存在错误时才渲染
|
||
|
|
if (!hasError) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
return <>{render({ errors: fieldErrors })}</>;
|
||
|
|
};
|