visual-novel-web/src/components/ui/radix-form/FormError.tsx

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 })}</>;
};