React七Formik

发布于:2025-02-26 ⋅ 阅读:(10) ⋅ 点赞:(0)

Formik是一个专为React构建的开源表单库。它提供了一个易于使用的API来处理表单状态管理,表单验证以及表单提交。Formik支持React中的所有表单元素和事件,可以很好地与React生态系统中的其他库集成。同时,Formik还提供了一些高级功能,如支持异步验证、字段级别的验证、根据表单状态变化自动计算属性等。

Formik 基础

Formik的优势,相较于传统的表单处理方法,Formik具有以下优势:

  • 状态管理: Formik自动地处理表单状态管理,无需手动编写大量的状态管理逻辑。
  • 表单验证: Formik提供了易于使用的表单验证工具,可以快速实现表单验证逻辑。
  • 表单提交: Formik可以方便地处理表单提交,包括异步表单提交和重试机制。
  • 支持复杂表单: Formik支持处理包括多级嵌套、动态表单、数组表单等多种复杂表单。

Formik 安装和简单使用

1、Formik安装,使用npm或yarn安装Formik。在终端中,切换项目目录并运行此命令 npm install formikyarn add formik

2、表单数据绑定以及提交处理

useFormik HOOK 参数说明:

  • initialValues:传递定义的输入HTML元素的name属性相匹配的初始值
  • onSubmit:提交程序,已经默认阻止了默认行为

onSubmit 属性定义了一个回调函数,在表单提交时被调用。在回调函数中可以访问表单中所有输入框的值并执行提交操作,通过 setSubmitting 函数,可以设置表单的提交状态。在表单的渲染函数中通过 handleSubmit 属性来处理表单的提交,使用 isSubmitting(默认false) 属性来禁用提交按钮,直到表单提交完成。

        const formik = useFormik({
            initialValues: {
                username: '',
                password: ''
            },
            onSubmit: (values, {setSubmitting}) => {
                // formik 已经默认帮我们阻止了默认执行
                console.log('values: ', values);
                setSubmitting(true)
            }
        })
        ……
        
            <form onSubmit={formik.handleSubmit}>
                <div>
                    <label htmlFor="username">用户名:</label>
                    <input id="username" type="text" name="username" value={formik.values.username} onChange={formik.handleChange}></input>
                </div>
                <div>
                    <label htmlFor="password">密码:</label>
                    <input id="password" type="password" name="password" value={formik.values.password} onChange={formik.handleChange}></input>
                </div>
                <button type="submit" disabled={formik.isSubmitting}>提交</button>
            </form>

useFormik 返回对象属性解释:

  • handleSubmit:提交处理程序
  • handleChange:传递给每个<input><select>、 或<textarea>的更改处理程序
  • values:表单的当前值,使用 name 访问对应的值
  • handleChange:每个 HTML 输入重用相同的更改处理函数
  • setValues和setFieldValue:setValues设置formik的values属性值,setFieldValue设置values的某一个属性值,二者写法不同,但是目的一样改变values的值。

如果没有 formik,那么就得一个个写change事件。

3、表单校验

Formik 不仅跟踪表单values,还跟踪其验证和错误消息。要使用 JS 添加验证,需指定一个自定义验证函数并将其传递给钩子 useFormik() 的参数 validate。如果存在错误,这个自定义验证函数应该生成一个匹配的error对象。

            validate: values => {
                const errors = {}
                if (!values.username) {
                    errors.username = '请输入用户名'
                } else if (values.username.length < 6 || values.username.length > 16) {
                    errors.username = '请输入6~16位的用户名'
                } else if (!/^\w{6,16}$/.test(values.username)) {
                    errors.username = '请输入由字母、数字、下划线组成的用户名'
                }
                if (!values.password) {
                    errors.password = '请输入密码'
                } else if (values.password.length < 6 || values.password.length > 16) {
                    errors.password = '请输入6~16位的密码'
                } else if (!/^\w{6,16}$/.test(values.password)) {
                    errors.password = '请输入由字母、数字、下划线组成的密码'
                }
                console.log('errors: ', errors);
                return errors
            }

默认情况下,Formik 将在每次击键(onChange)事件以及提交之前进行验证。传递 formik.handleBlur 给输入元素的 onBlur 属性,那么会在输入元素的失焦(onBlur)事件中进行验证:

    <input id="username" type="text" name="username" value={formik.values.username} onChange={formik.handleChange} onBlur={formik.handleBlur}></input>

校验确实实现了,但是如果希望在提交表单的时候再显示错误,需要怎么做呢?
Formik 会跟踪哪些字段已被访问过。它将这些信息存储在一个名为 touched 的对象中,这些值为boolean值。

        <p>{formik.touched.username && formik.errors.username ? formik.errors.username : ''}</p>

Formik 结合 Yup 进行表单验证

Yup是一个构建对象模式的JavaScript模式验证器,用于验证和解析数据。它提供了一种声明式方法来创建校验模式。

由于 Formik 作者/用户非常喜欢Yup,因此 Formik 有一个名为 Yup 的特殊配置道具validationSchema,它会自动将 Yup 的验证错误消息转换为一对象。

1、Yup 安装 npm install yupyarn add yup

2、使用 Yup 校验表单:

  • Formik 结合 Yup 可以轻松实现表单验证 validationSchema={Yup.object({...})},使用 validationSchema 和 Yup 搭配之后就不需要再使用validate配置了。
  • Yup 允许创建复杂的校验逻辑,如必填项、字符长度、正则表达式等。
            validationSchema: Yup.object({
                username: Yup.string().required('请输入用户名')
                    .min(6, '请输入6~16位的用户名')
                    .max(16, '请输入6~16位的用户名')
                    .matches(/^\w{6,16}$/, '请输入由字母、数字、下划线组成的用户名'), 
                password: Yup.string().required('请输入密码')
                    .min(6, '请输入6~16位的密码')
                    .max(16, '请输入6~16位的密码')
                    .matches(/^\w{6,16}$/, '请输入由字母、数字、下划线组成的密码')
            })

Formik 组件

以上都是通过 useFormik 拿到控制formik表单的内容,但是这样不容易形成封装,也就是说无法进行实例传值。而Formik由于配备了React Context,因此Formik本身就可以管理所包裹的JSX。

formik完全遵守React的组件化原则,可以和其他库或自定义逻辑无缝集成:

  • formik支持构建和复用表单组件,通过<Formik />组件和Context API实现跨组件通信。
  • 可以创建包装<Field />ErrorMessage等的自定义组件,提高代码复用性和可维护性。
            <Formik 
            initialValues={{username: '', password: ''}} // 设置初始化值
            onSubmit={(values, {setSubmitting}) => { // 提交表单执行的函数
                setTimeout(() => {
                    console.log('values: ', values); 
                    setSubmitting(true)
                }, 2000);
            }}
            validationSchema={Yup.object({ // 设置表单校验的模式
                username: Yup.string().required('请输入用户名')
                    .min(6, '请输入6~16位的用户名')
                    .max(16, '请输入6~16位的用户名')
                    .matches(/^\w{6,16}$/, '请输入由字母、数字、下划线组成的用户名'), 
                password: Yup.string().required('请输入密码')
                    .min(6, '请输入6~16位的密码')
                    .max(16, '请输入6~16位的密码')
                    .matches(/^\w{6,16}$/, '请输入由字母、数字、下划线组成的密码')
            })}
            >
                {({handleSubmit, values, touched, handleChange, handleBlur, errors, isSubmitting}) => {
                    return <form onSubmit={handleSubmit}>
                        <div>
                            <label htmlFor="username1">用户名:</label>
                            {/* <input id="username1" type="text" name="username" value={values.username} onChange={handleChange} onBlur={handleBlur}></input> */}
                            <Field id='username1' name='username' type='text'></Field>
                            {/* <p>{touched.username && errors.username ? errors.username : ''}</p> */}
                            <ErrorMessage name="username"></ErrorMessage>
                        </div>
                        <div>
                            <label htmlFor="password1">密码:</label>
                            <input id="password1" type="password" name="password" value={values.password} onChange={handleChange}></input>
                            <p>{touched.password && errors.password ? errors.password : ''}</p>
                        </div>
                        <button type="submit" disabled={isSubmitting}>提交</button>
                    </form>
                }}
            </Formik>
常用组件

1、ErrorMessage 捕捉错误的容器,必传一个name属性。

    <ErrorMessage name="username"></ErrorMessage>

2、Field 将自动将输入连接到 Formik,默认渲染是input输入框,有以下几种方法渲染:

    function MyField({field, form}) {
        console.log('field: ', field);
        console.log('form: ', form);
        return <input {...field}></input>
    }
    ……
            <Formik 
            initialValues={{email: '', project: 2, phone: '', address: '1'}} // 设置初始化值
            onSubmit={(values) => { console.log('values: ', values); }} // 提交表单执行的函数
            validationSchema={Yup.object({ // 设置表单校验的模式
                phone: Yup.string().required('请输入电话号码')
                    .matches(/^1[0-9]{10}/, '请输入有效的电话号码')
            })}
            >
                {({handleSubmit}) => {
                    return <form onSubmit={handleSubmit}>
                        {/* 1、直接渲染 */}
                        <Field type='email' name='email' placeholder='请输入电子邮箱'></Field> <br/>

                        {/* 2、as 转化成其他节点 */}
                        <Field as='select' name='project'>
                            <option value={1}>数学及应用数学</option>
                            <option value={2}>软件工程</option>
                            <option value={3}>国际贸易</option>
                        </Field> <br/>

                        {/* 3、渲染 jsx */}
                        <Field name='phone'>
                            {({field, form, meta}) => {
                                console.log('field: ', field);
                                console.log('form: ', form);
                                console.log('meta: ', meta);
                                return <div>
                                    <label htmlFor="phone">电话号码</label>
                                    <input id="phone" type="text" placeholder="请输入电话号码" value={field.value.phone} {...field}></input>
                                    <p>{ meta.touched && meta.error ? meta.error : ''}</p>
                                </div>
                            }}
                        </Field>

                        {/* 4、以 component 组件形式渲染 */}
                        <Field name='address' component={MyField}></Field> <br />
                        <button type="submit">提交</button>
                    </form>
                }}
            </Formik>

数组和对象校验

Formik 支持嵌套对象和数组:

  • yup 对象校验使用 Yup.object({})
  • yup 数组校验使用 Yup.array().of()
        <Formik
        initialValues={{social: {wechat: '', qq: ''}, frends: ['', '']}}
        onSubmit={(values, {setSubmitting}) => {
            console.log('values: ', values)
            setSubmitting(true)
        }} 
        validationSchema={Yup.object({
            social: Yup.object({
                wechat: Yup.string().required('请输入微信'), 
                qq: Yup.string().required('请输入QQ').matches(/^[\w]$/, '请输入有效的QQ')
            }),
            frends: Yup.array().of(Yup.string().required('请输入你的朋友'))
        })}>
            {({values, handleChange, handleBlur, touched, errors, isSubmitting, setValues, setFieldValue}) => {
                console.log('object array values: ', values);
                console.log('object array handleChange: ', handleChange);
                console.log('object array handleBlur: ', handleBlur);
                console.log('object array touched: ', touched);
                console.log('object array errors: ', errors);
                console.log('object array setValues: ', setValues);
                console.log('object array setFieldValue: ', setFieldValue);
                
                return <form>
                    <h4>社交账号</h4>
                    <label>微信:</label>
                    <input name="social.wechat" value={values.social.wechat} onChange={handleChange} onBlur={handleBlur}></input>
                    <p>{ touched.social && errors.social && touched.social.wechat && errors.social.wechat ? errors.social.wechat : ''}</p>
                    <br />
                    <label>QQ:</label>
                    <input name="social.qq" value={values.social.qq} onChange={handleChange} onBlur={handleBlur}></input>
                    <h4>朋友</h4>
                    {values.frends.map((v, i) => {
                        return (<div key={i}>
                            <input name={`friends[${i}]`} onChange={handleChange} onBlur={handleBlur}></input>
                            {i < values.frends.length && <br />}
                        </div>)
                    })}
                    <button type="submit" disabled={isSubmitting}>提交</button>
                </form>}}
        </Formik>

网站公告

今日签到

点亮在社区的每一天
去签到