在TS环境中React Hook Form表单的创(二)

—————-书接上篇文章————-

验证时机

默认情况下,当单击登录按钮时进行验证。一旦进行了一次验证,之后每次输入文本都会触发验证。

你可以通过useForm的两个选项modereValidateMode来控制何时进行验证。还可以手动触发验证。

设置mode

单击登录按钮时进行验证是由mode选项控制的。默认值是”onSubmit”,但可以更改为”onBlur”、”onChange”、”onTouched”或”all”。虽然从值的名称就可以想象出每个选项的行为,但将mode的值从”onSubmit”更改为”onChange”会有什么变化,下面我们来看看。

 const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    criteriaMode'all',
    defaultValues: {
        email'243425345@qq.com',
        password'1233444'
    },
    mode'onChange'
 });

“onChange”是根据每次输入的文字触发验证,因为它使用了onChange事件。

当使用useState Hook和onChange事件时,每次输入都会导致重新渲染。但是,当将mode设置为”onChange”时,重新渲染不会在每次输入文字时触发,而是在验证消息的显示/隐藏切换时触发。

如果将mode更改为”onBlur”,则在将光标从输入框中移出时进行验证。

const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    criteriaMode'all',
    defaultValues: {
        email'243425345@qq.com',
        password'1233444'
    },
    mode'onBlur'
 });
reValidateMode的设置

reValidateMode用于设置第二次及以后的验证时机。默认情况下,单击登录按钮后进行验证,之后每次输入都会触发验证。您可以使用reValidateMode来设置第二次验证的时机,默认值是”onChange”,但也可以更改为”onBlur”或”onSubmit”。

const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    criteriaMode'all',
    defaultValues: {
        email'243425345@qq.com',
        password'1233444'
    },
    reValidateMode'onSubmit'
});

如果将值更改为onSubmit,则仅当您单击登录按钮时才会执行验证。

手动验证

可以使用触发器手动完成验证,触发器是 useForm 返回的对象的属性之一。

 const { register, handleSubmit, formState: { errors } ,trigger} = useForm<FormData>({
    criteriaMode'all',
    defaultValues: {
        email'243425345@qq.com',
        password'1233444'
    },
});
//略
<div>
  <button type="submit">登录</button>
  <button type="button" onClick={() => trigger()}>验证</button>
</div>

单击验证按钮执行验证。如果触发器参数中未设置任何内容,将对所有输入项执行验证。如果只想验证密码,请设置触发器(’password’)以仅验证密码。

事实证明,你可以使用 modereValidateMode 和触发器trigger来控制验证的时间。

“dirty”的设置

为了显示错误消息,我们使用了formState对象的”errors“属性,但除了”errors“属性外,还包含了其他重要的信息可用于表单。”dirty“的设置可以通过使用”isDirty“和”dirtyFields“来进行。

设置”isDirty”

formState对象有一个属性叫做”isDirty“。通过使用”isDirty“属性,你可以检查用户是否已经在表单的任何输入字段中输入了任何字符。默认情况下,”isDirty“的值为false,但当用户在表单的任何输入字段中输入一个字符时,”isDirty“的值会从false更改为true。

例如,当页面刚打开时,可以通过将”isDirty“设置为登录按钮的disable属性,使按钮无法点击。但是,当用户将焦点放在Email或Password输入字段上并输入字符时,”isDirty“将从true更改为false,使登录按钮变为可点击状态。

 const { register, handleSubmit, formState: { errors ,isDirty} } = useForm<FormData>({
    criteriaMode'all',
    defaultValues: {
        email'',
        password''
    },
});
//略
 <div>
      <button type="submit" disabled={!isDirty}>登录</button>
</div>

在浏览器中进行操作验证后,正如所描述的,当页面刚打开时,无法立即单击登录按钮。要单击登录按钮,必须在Email或Password字段中输入文本。

在TS环境中React Hook Form表单的创(二)
image.png
配置isDirty

“isDirty”属性用于检查整个表单中是否已经输入内容,而”dirtyFields”属性则允许您分别检查每个输入字段(字段)的”dirty”状态。

要检查Email输入字段是否已经输入内容,可以使用dirtyFields.email来确认。如果为Email字段设置了默认值,只有在输入与默认值不同的字符时,才能单击按钮。与isDirty不同,这不会受到Password输入字段的影响。

function App({
    const { register, handleSubmit, formState: { errors ,dirtyFields} } = useForm<FormData>({
    criteriaMode'all',
    defaultValues: {
        email'',
        password''
    },
});
//略
<div>
  <button type="submit" disabled={!dirtyFields.email}>登录</button>
</div>

你也可以配置邮箱和密码不为空时才能点击按钮,如下代码:

 <div>
      <button type="submit" disabled={!dirtyFields.email || !dirtyFields.password}>登录</button>
  </div>

其他 formState 属性

除了错误errorsisDirtydirtyFields 之外,formState 属性还包括以下属性。

  • touchedFields
  • isSubmitted
  • isSubmitSuccessful
  • isSubmitting
  • submitCount
  • isValid
  • isValidating
touchedFields

通过使用touchedFields,你可以确定是否在每个输入字段上放置光标并移除它。touchedFields最初是一个空对象,但当你将光标放在Email输入字段上并将其移除时,将添加像下面这样的email属性。

{
    "email"true
}

此外,当你将光标放在Password输入字段上并将其移除时,将添加像下面这样的password属性。

{
    "email"true,
    "password"true
}
isSubmitted

isSubmitted属性用于在点击登录按钮后将其从false更改为true。

isSubmitting

isSubmitting属性在执行提交操作期间(通过点击登录按钮)从false更改为true。它可用于防止在提交处理中多次触发按钮。

为了确认submitCountisSubmittedisSubmitting属性如何变化,你可以在登录按钮上方添加以下代码。

function App({
    const { register, handleSubmit, formState: {
            errors,
            dirtyFields,
            isSubmitted,
            isSubmitting,
            submitCount,
        }
    } = useForm<FormData>({
        criteriaMode'all',
        defaultValues: {
            email'',
            password''
        },
    });
     const onSubmit = handleSubmit(async (data) => {
        await new Promise((resolve) => setTimeout(resolve, 5000));
        console.log(data);
    });
 //省略
 <div>
      <strong> submitCount : </strong> {JSON.stringify(submitCount)}
    </div>

    <div>
      <strong> isSubmitted : </strong> {JSON.stringify(isSubmitted)}
    </div>

    <div>
      <strong> isSubmitting : </strong> {JSON.stringify(isSubmitting)}
</div>


<div>
      <button type="submit" disabled={!dirtyFields.email || !dirtyFields.password}>登录</button>
</div>
          

在handle函数中添加延迟代码来检查isSubmitting的值是否发生变化。等待 5 秒钟以完成该过程。

输入通过验证的代码后,单击“登录”按钮。

最初,submitCount的值为0,isSubscribedisSubmitting的值为false。在TS环境中React Hook Form表单的创(二)

点击登录按钮后:在TS环境中React Hook Form表单的创(二)

然后过了5秒钟之后:在TS环境中React Hook Form表单的创(二)

单击登录按钮时,只有 isSubmiting 的值从 true 更改为 false。5秒后,isSbumitting的值从true变为false,submitCount从0变为1,isSubscribed从false变为true。如果再次点击登录按钮,则submitCount的值为2。

submitCount

submitCount属性用于保存已执行的提交操作(通过点击登录按钮)的次数。

isValid

要进行isValid的操作验证,你可以使用它来确认验证是否失败。默认情况下,isValid为false,但如果通过了所有验证且没有错误,它将变为true。

以下是如何配置以仅在验证通过时使按钮可点击的设置:

import React from 'react';
import { useForm } from 'react-hook-form';

function App({
  const { register, handleSubmit, formState: { dirtyFields, isValid }, reset } = useForm();
  
  const onSubmit = (data) => {
    // 处理表单提交逻辑
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>Email</label>
      <input {...register('email')} />

      <label>Password</label>
      <input type="password" {...register('password')} />

      <button type="submit" disabled={!isValid}>
        登录
      </button>
    </form>

  );
}

export default App;

在这个示例中,我们使用isValid属性来确定验证是否通过。只有当isValid为true时,登录按钮才会设置为可点击状态。如果有任何验证错误,isValid将保持为false,按钮将保持禁用状态。这确保了只有在所有验证都通过时,才能提交表单。

reset 重新设置

通过使用reset函数,你可以重置表单中输入的值以及formState中包含的属性值。

要添加重置按钮,并在单击按钮时执行reset函数以确认formState的属性如何变化,可以使用以下代码进行操作。reset函数的参数指定了每个字段的值在重置后应设置为什么值。在这里,我们将值设置为与useFormdefaultValues相同,但您也可以设置为其他值。重置按钮的type属性设置为”reset”。

import './App.css'
import {SubmitHandler, useForm} from "react-hook-form";
import {Simulate} from "react-dom/test-utils";
import reset = Simulate.reset;
type FormData = {
    email:string;
    password:string
}

function App({
    const { register, handleSubmit,reset, formState: {
            errors,
            isValid,
            isDirty,
            dirtyFields,
            isSubmitted,
            isSubmitting,
            submitCount,
        }
    } = useForm<FormData>({
        defaultValues: {
            email'',
            password''
        },
    });
    const onSubmit = handleSubmit( (data) => {
        console.log(data);
    });
    const handleReset = () => {
        reset({
            email'',
            password''
        })
    }
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={onSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  {...register('email',{required:'邮箱不能为空!'})}
              />

              {errors.email?.message && <div style={{color:'red'}}>{errors.email.message}</div>}
              {/*{errors.email && <div style={{color:'red'}}>请先填写邮箱</div>}*/}
          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  {...register('password',{
                      required: {
                          value: true,
                          message: '密码不能为空!'
                      },
                      pattern: {
                          value: /^[A-Za-z]+$/,
                          message: '请仅输入字母字符',
                      },
                      minLength: {
                          value: 8,
                          message:'密码长度不能少于8位数'
                      }
                  })}
              />

              {errors.password?.type === 'required' && (
                  <div style={{color:'red'}}>{errors.password.message}</div>
              )}
              {errors.password?.types?.pattern && (
                  <div style={{color:'red'}}>{errors.password.types.pattern}</div>
              )}
              {errors.password?.type === 'minLength' && (
                  <div style={{color:'red'}}>{errors.password.message}</div>
              )}
          </div>
          <div>isValid : {JSON.stringify(isValid)}</div>
          <div>isDirty : {JSON.stringify(isDirty)}</div>
          <div>
              <strong> submitCount : </strong> {JSON.stringify(submitCount)}
          </div>
          <div>
              <strong> isSubmitted : </strong> {JSON.stringify(isSubmitted)}
          </div>
          <div>
              <strong> isSubmitting : </strong> {JSON.stringify(isSubmitting)}
          </div>

          <div>
              <button type="submit" disabled={!dirtyFields.email || !dirtyFields.password}>登录</button>
              <button type="reset" onClick={handleReset}>
                  重置
              </button>
          </div>
      </form>
    </>

  )
}

export default App

输入时,isValidisDirty 的值变为 true,并将 email 和 password 属性添加到 touchFields 对象中,值变为 true。在TS环境中React Hook Form表单的创(二)

当点击Rest按钮时,可以看到isValidisDirty从true变为false,并且touchedFields的值也被重置。由于没有执行提交,submitCountisSubscribed 值保持不变。

在TS环境中React Hook Form表单的创(二)
image.png

在某些情况下,你可能希望在提交过程成功完成后重置,而不是使用重置按钮,因此将 Reset 函数添加到 onSubmit 函数中。

const onSubmit = handleSubmit((data) => {
  console.log(data);
  reset({
    email'',
    password'',
  });
});

点击登录按钮提交时,就把数据重置为空了。

文档建议在提交后在useEffect内执行重置。我们来检查一下在useEffect内部执行reset函数是否会有什么不同。在useEffect的依赖项中,我们设置了isSubmitSuccessful,该值在提交成功时更改。在onSubmit函数内部,我们对reset函数进行了注释。

import { useEffect } from 'react'
import './App.css'
import { useForm} from "react-hook-form";

type FormData = {
    email:string;
    password:string
}

function App({
    const { register, handleSubmit,reset, formState: {
            errors,
            isValid,
            isDirty,
            dirtyFields,
            isSubmitted,
            isSubmitting,
            submitCount,
            isSubmitSuccessful
        }
    } = useForm<FormData>({
        defaultValues: {
            email'',
            password''
        },
    });
    useEffect(() => {
        reset({
            email'',
            password''
        })
    }, [isSubmitSuccessful]);

    const onSubmit = handleSubmit( (data) => {
        console.log(data);
        // reset({
        //     email: '',
        //     password: '',
        // });
    });
    const handleReset = () => {
        reset({
            email'',
            password''
        })
    }
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={onSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  {...register('email',{required:'邮箱不能为空!'})}
              />

              {errors.email?.message && <div style={{color:'red'}}>{errors.email.message}</div>}
              {/*{errors.email && <div style={{color:'red'}}>请先填写邮箱</div>}*/}
          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  {...register('password',{
                      required: {
                          value: true,
                          message: '密码不能为空!'
                      },
                      pattern: {
                          value: /^[A-Za-z]+$/,
                          message: '请仅输入字母字符',
                      },
                      minLength: {
                          value: 8,
                          message:'密码长度不能少于8位数'
                      }
                  })}
              />

              {errors.password?.type === 'required' && (
                  <div style={{color:'red'}}>{errors.password.message}</div>
              )}
              {errors.password?.types?.pattern && (
                  <div style={{color:'red'}}>{errors.password.types.pattern}</div>
              )}
              {errors.password?.type === 'minLength' && (
                  <div style={{color:'red'}}>{errors.password.message}</div>
              )}
          </div>
          <div>isValid : {JSON.stringify(isValid)}</div>
          <div>isDirty : {JSON.stringify(isDirty)}</div>
          <div>
              <strong> submitCount : </strong> {JSON.stringify(submitCount)}
          </div>
          <div>
              <strong> isSubmitted : </strong> {JSON.stringify(isSubmitted)}
          </div>
          <div>
              <strong> isSubmitting : </strong> {JSON.stringify(isSubmitting)}
          </div>

          <div>
              <button type="submit" disabled={!dirtyFields.email || !dirtyFields.password}>登录</button>
              <button type="reset" onClick={handleReset}>
                  重置
              </button>
          </div>
      </form>
    </>

  )
}

export default App

填写表单并且点击登录按钮后,浏览器执行后是这样子的:在TS环境中React Hook Form表单的创(二)

useEffect内部执行reset函数时,可以观察到submitCountisSubmitted的值也被重置。尽管屏幕上看不到值的变化,但isSubmitted的值会变为true,submitCount的值会变为1。如果不想重置这些值,可以在reset函数的选项中进行设置。以下示例演示如何不重置submitCountisSubmittedtouchedFields的值:

useEffect(() => {
  reset(
    {
      email'',
      password'',
    },
    {
      keepSubmitCounttrue,
      keepIsSubmittedtrue,
      keepTouchedtrue,
    }
  );
}, [isSubmitSuccessful]);

填写表格并单击“登录”按钮之后的效果:在TS环境中React Hook Form表单的创(二)

同样的,我们也可以在onSubmit函数中设置选项:

const onSubmit = handleSubmit((data) => {
  console.log(data);
  reset(
    {
      email'',
      password'',
    },
    {
      keepSubmitCountfalse,
      keepIsSubmittedfalse,
      keepTouchedtrue,
    }
  );
});

设置setError

对于前端验证错误,我们已经了解了如何使用React Form Hook来显示它们。但是,对于后端验证错误,可以使用setError来将从后端接收到的错误添加到React Hook Form的错误中。

以下是一个示例代码,在这个示例中,当点击登录按钮后,onSubmit函数会抛出一个错误,然后使用setError函数将错误添加到Email字段的错误中:


import './App.css'
import { useForm} from "react-hook-form";

type FormData = {
    email:string;
    password:string
}

function App({
    const { register, handleSubmit,setError, formState: {
            errors
        }
    } = useForm<FormData>({
        defaultValues: {
            email'',
            password''
        },
    });

    const onSubmit = handleSubmit((data) => {
        console.log(data);
       try {
           throw new Error('发生错误啦!')
       }catch (error: any) {
            setError('email',{
                type'server',
                message: error.message
            })
           console.log(error.message);
       }
    });
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={onSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  {...register('email',{required:'邮箱不能为空!'})}
              />

              {errors.email?.message && <div style={{color:'red'}}>{errors.email.message}</div>}
              {/*{errors.email && <div style={{color:'red'}}>请先填写邮箱</div>}*/}
          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  {...register('password',{
                      required: {
                          value: true,
                          message: '密码不能为空!'
                      },
                      pattern: {
                          value: /^[A-Za-z]+$/,
                          message: '请仅输入字母字符',
                      },
                      minLength: {
                          value: 8,
                          message:'密码长度不能少于8位数'
                      }
                  })}
              />

              {errors.password?.type === 'required' && (
                  <div style={{color:'red'}}>{errors.password.message}</div>
              )}
              {errors.password?.types?.pattern && (
                  <div style={{color:'red'}}>{errors.password.types.pattern}</div>
              )}
              {errors.password?.type === 'minLength' && (
                  <div style={{color:'red'}}>{errors.password.message}</div>
              )}
          </div>

          <div>
              <button type="submit">登录</button>

          </div>
      </form>
    </>

  )
}

export default App

填写表单并单击“登录”按钮时,将显示 setError 中设置的消息。在TS环境中React Hook Form表单的创(二)

显示输入的值

要显示输入的值,有多种方法可供选择,但在这里,我们将查看包含在从useForm返回的对象中的getValueswatch

watch可以用于获取值,但更重要的是,它允许你监视输入元素的输入,以便立即检测到值的更改。

这两种方法都可以用于获取输入的值,但使用watch时,每次输入都会触发重新渲染。

使用 getValues 检索

getValues可以用于获取表单中设置的所有值,也可以用于获取单个值。

要获取Email字段中的值,可以在表单内添加以下代码。但是,请注意,即使你在Email输入字段中输入值,也不会立即显示值。这是因为useForm的默认modeonSubmit,只有在提交时才会获取值。如果要在输入时立即获取值,可以将mode更改为onChangeonBlur等选项。

function App({
  const {
    register,
    handleSubmit,
    getValues,
    formState: { errors },
  } = useForm<FormData>({
    defaultValues: { email''password'' },
    criteriaMode'all',
  });
  //略
<div>{getValues('email')}</div>

如果要显示 getValues 的值,则需要重新绘制它。默认情况下,单击登录按钮时会重绘,因此当您完成输入并单击登录按钮时,输入的值将显示在屏幕上。在TS环境中React Hook Form表单的创(二)

通过watch获取

getValues 类似,watch 可以检索所有值,但它也可以检索单个值。

在表单中添加以下代码以检索电子邮件中输入的值。还要设置getValues,其值是通过重新渲染来显示的。

function App({
  const {
    register,
    handleSubmit,
    getValues,
    watch,
    formState: { errors },
  } = useForm<FormData>({
    defaultValues: { email''password'' },
    criteriaMode'all',
  });
  //略
<div>{watch('email')}</div>
<div>{getValues('email')}</div>

与单独的 getValues 不同,每次您在电子邮件中键入字符时,都会显示您键入的值。由于watch被重绘,getValues的值也被更新,并且watchgetValues都实时显示输入的值。

使用watch的实例

在文档中已经有关于如何使用watch的示例,让我们来确认一下如何使用它。在这里,我们将使用watch来监视showAge的输入值。watch的第二个参数可以设置初始值,这里设置为falsewatchShowAge将保存age的值,当勾选复选框时,它的值从false变为true,只有在选中时才会显示输入元素。


import './App.css'
import { useForm} from "react-hook-form";

type FormData = {
    showAge: boolean;
    age: string
}

function App({
    const { register, handleSubmit, watch,formState: {
            errors
        }
    } = useForm<FormData>();
    const watchShowAge = watch('showAge',false);

    const onSubmit = handleSubmit((data) => {
        console.log(data);
    });
    return (
    <>
      <form onSubmit={onSubmit}>
          <div>
              <input type="checkbox" {...register('showAge')}/>
          </div>
          {
              watchShowAge && (
                  <div>
                      <input type="number" {...register('age',{min:50})}/>
                      {errors.age && <div style={{color:"red"}}>请输入50或以上</div>}
                  </div>
              )
          }

          <div>
              <button type="submit">发送</button>
          </div>
      </form>
    </>

  )
}

export default App
在TS环境中React Hook Form表单的创(二)
image.png

使用watch监视复选框值,如果选中该复选框,将显示输入元素。在TS环境中React Hook Form表单的创(二)

输入值,点击发送的时候,触发onSubmit函数

在TS环境中React Hook Form表单的创(二)
image.png

如果该篇文章对你有用的话,就请点点关注吧!一起学习前端知识

原文始发于微信公众号(大前端编程教学):在TS环境中React Hook Form表单的创(二)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/224471.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!