我正在尝试做的事情:
我正在构建一个复杂的表单,需要一种方法来根据某些条件(主要是正则表达式)提供提示和警告消息,而不阻止表单提交。本质上,这些消息将充当一种软验证形式,以帮助用户完成更高质量的表单。我想找到一个与 React Hook Form V7 配合良好的解决方案。
问题:
React Hook Form V7 仅支持硬验证(又名阻止表单提交)。据我所知,根据此 rhf 功能请求,没有计划在不久的将来添加此功能的支持。
可能的解决方案:
上述 rhf 功能请求中提出了一些 V6 解决方案,例如 rhf 创建者的这个:
const PowerController = (props: Props) => {
const { formState } = useFormContext();
const isDirty = !!formState.dirtyFields[props.name];
const isTouched = !!formState.touched[props.name];
return (
<Controller
control={props.control}
name={props.name}
defaultValue={props.defaultValue}
render={(innerProps) => {
return props.render({
...innerProps,
isDirty,
isTouched,
warning: props.warn(innerProps.value)
});
}}
/>
);
};
我还找到了关于如何使用 rhf 触发自定义 onChange 的答案,建议是将
onChange
传递给 Controller
或 useWatch()
。 链接在这里。
我喜欢将自定义
onChange
传递给 Controller
解决方案,但如果我理解正确,这样做将取代 onChange
中内置的 Controller
。我不确定如何进行这项工作,因为我只是想添加一些功能(又名字段更改的软验证)。
使用 useWatch() 的解决方案来查看值何时发生变化,然后有一个单独的
useEffect()
,我将软验证逻辑放入其中似乎很合理,但复杂的形式可能会变得非常混乱??
我需要什么帮助:
任何有关哪种方法最好的建议和/或有关如何调整电源控制器 V6 解决方案以与V7控制器配合使用的想法,我们将不胜感激。我刚刚学习 rhf,希望在我花几周时间用头撞墙试图解决这个问题之前得到一些输入,哈哈。
我也遇到了同样的问题,发现重构提议的codesandbox解决方案以与rhf v7一起使用并不难(升级版本时的沙箱消息实际上很有帮助。
这是一个分叉版本,希望对您有所帮助 -
https://codesandbox.io/s/extend-controller-forked-v7-upgrade-iyw5p0?file=/src/App.tsx
我设法让 PowerController 工作,但是,它不符合我们的需求,因为我们使用了 useController 钩子。
为了实现与提供的 PowerController 示例相同的功能,我编写了一个自定义挂钩。
import { FieldValues, FieldPath, UseControllerProps, UseControllerReturn, useController } from "react-hook-form";
type UsePowerControllerProps<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = UseControllerProps<TFieldValues, TName> & {
warn: (value: string) => boolean | string;
}
type UsePowerControllerReturn<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = UseControllerReturn<TFieldValues, TName> & {
warning: string | boolean
}
/**
* Custom hook to work with controlled component, this function provide you with both form and field level state. Re-render is isolated at the hook level.
*
* @remarks
* [API](https://react-hook-form.com/docs/usecontroller) • [Demo](https://codesandbox.io/s/usecontroller-0o8px)
*
* @param props - the path name to the form field value, and validation rules.
*
* @returns field properties, field and form state. {@link UsePowerControllerReturn}
*
* @example
* ```tsx
* function Input(props) {
* const { field, fieldState, formState } = usePowerController(props);
* return (
* <div>
* <input {...field} placeholder={props.name} />
* <p>{fieldState.isTouched && "Touched"}</p>
* <p>{formState.isSubmitted ? "submitted" : ""}</p>
* </div>
* );
* }
* ```
*/
export function usePowerController<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>(
props: UsePowerControllerProps<TFieldValues, TName>,
): UsePowerControllerReturn<TFieldValues, TName> {
const { field, fieldState, formState } = useController(props);
return { field, fieldState, formState, warning: props.warn(field.value) }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>
以及如何使用挂钩;
const {
field
fieldState: { error },
warning,
} = usePowerController({
name: 'yourField',
control: control,
warn: (value: any) => {
// do some soft validation here
return false;
},
});
如果您有任何改进,请告诉我!