Formik 和 Material-UI
Posted
技术标签:
【中文标题】Formik 和 Material-UI【英文标题】:Formik and Material-UI 【发布时间】:2019-02-06 05:59:48 【问题描述】:我正在尝试将 Formik 与 Material-UI 文本字段一起使用。像这样:
import TextField from '@material-ui/core/TextField';
import
Field,
FieldProps,
Form,
Formik,
FormikErrors,
FormikProps
from 'formik';
import React, Component from 'react';
interface IMyFormValues
firstName: string;
class CreateAgreementForm extends Component<>
public render()
return (
<div>
<h1>My Example</h1>
<Formik
initialValues= firstName: ''
// tslint:disable-next-line:jsx-no-lambda
onSubmit=(values: IMyFormValues) => alert(JSON.stringify(values))
// tslint:disable-next-line:jsx-no-lambda
validate=(values: IMyFormValues) =>
const errors: FormikErrors<IMyFormValues> = ;
if (!values.firstName)
errors.firstName = 'Required';
return errors;
// tslint:disable-next-line:jsx-no-lambda
render=(formikBag: FormikProps<IMyFormValues>) => (
<Form>
<Field
name="firstName"
render=( field, form : FieldProps<IMyFormValues>) => (
<TextField
error=Boolean(
form.errors.firstName && form.touched.firstName
)
helperText=
form.errors.firstName &&
form.touched.firstName &&
String(form.errors.firstName)
/>
)
/>
</Form>
)
/>
</div>
);
export default CreateAgreementForm;
我希望 Formik 负责外观的验证和 Material-UI。 我想将 errors.firstName 传递给 TextField 组件,但错误显示不正确。我怎样才能修复它,这样它仍然可以清楚地阅读?我不想编写自己的 TextField 组件。
【问题讨论】:
我不知道如何将 Material-ui 组件与 Formik 验证集成,但我可以推荐 react-final-form ,它与 MUI 集成得很好:github.com/final-form/react-final-form#material-ui-10 谢谢,但我仍然需要为每个 material-ui 组件创建自定义组件。我宁愿不要。你知道怎么做吗? 这看起来有点矫枉过正,但我们发现像这样包装 material-ui 表单组件实际上很简单直接。我认为您总是必须以某种方式将“FormXXX”框架道具映射到 Material-UI 组件。 你可以看看这个项目做了什么:github.com/stackworx/formik-material-ui/tree/master/src 我真的认为您应该考虑为每个 Material-UI 组件创建自定义组件。原因如下:不要重复自己(Formik API 到 MUI props 的映射是一次性完成的),限制未来 MUI 或 Formik 重大变化的影响。 【参考方案1】:我认为您不需要另一个库,甚至不需要创建自己的包装器,我认为您需要稍微调整一下代码。
您遇到的一个问题是您没有在 Material TextField 中传递 onChange 函数,因此 firstName 的表单值始终为空,因此即使您输入了名称,您也总是会收到错误消息。 尝试在 TextField 和 onChange 函数上添加名称或 ID,如下所示:
<Field
validateOnBlur
validateOnChange
name="firstName"
render=( field, form ) => (
<TextField
name="firstName"
error=
Boolean(form.errors.firstName && form.touched.firstName)
onChange=formikBag.handleChange
onBlur=formikBag.handleBlur
helperText=
form.errors.firstName &&
form.touched.firstName &&
String(form.errors.firstName)
/>
)
/>
【讨论】:
不行,还是不行。字段为空时不显示错误 出现错误,但目前您已将验证设置为在提交时显示。这意味着您需要按回车键才能显示它。如果您希望它们也出现 onChange 和 onBlur ,请参阅我更新的答案。希望这会有所帮助。 您会发现自己在每个“字段”实例中重复将道具映射到 Material-UI 组件道具,这就是为我创建 Material-UI 包装器的重点,集中此映射确实有意义在自定义组件中。想象有一天,MUI 或 Formik 的 API/Props 发生了重大变化。您只需要更新一个组件! 你说得对,包装组件是个好主意。但我认为在这里要做的第一件事是让它在单个领域工作,然后他可以专注于根据他需要构建的内容构建包装器。 这是要去的地方formik.org/docs/api/field#children【参考方案2】:正如 cmets 中提到的,实现“包装”组件实际上可能是一个好主意,就像他们在 Formik 或 ReactFinalForm 的示例中所做的那样:
https://github.com/stackworx/formik-material-ui/tree/master/src https://github.com/final-form/react-final-form#material-ui-10想法是一样的:实现自定义的“包装器”组件来包装 Material-UI 组件并映射 Formik 或 ReactFinalForm APIs props。
这种方法的优点是将两个框架之间的映射集中在一个地方,这样您就不必每次都重复映射,如果其中一个框架引入了重大更改,您只需更改那些自定义的“包装器” " 组件。
【讨论】:
【参考方案3】:你可以试试这个:https://github.com/daixianceng/formik-material-fields
安装:
npm install --save formik-material-fields
用法:
import React, Component from 'react';
import Formik, Form from 'formik';
import * as Yup from 'yup';
import FormikTextField from 'formik-material-fields';
const validationSchema = Yup.object().shape(
username: Yup.string().required(),
);
const initialValues =
username: '',
;
class MyForm extends Component
render()
return (
<Formik
initialValues=initialValues
validationSchema=validationSchema
onSubmit=this.props.onSubmit
>
( isValid ) => (
<Form autoComplete="off">
<FormikTextField
name="username"
label="Username"
margin="normal"
fullWidth
/>
</Form>
)
</Formik>
);
【讨论】:
很好的答案!谢谢 对于需要快速简单 UI 的后端人员来说,这个库太棒了!【参考方案4】:您也可以试试这个库,它为您完成了繁重的工作并实现了 Material-UI 组件周围的包装代码(包括 <TextField />
):https://github.com/stackworx/formik-material-ui。
安装:
yarn add formik-material-ui
在您的 Formik 表单组件中,将 <TextField />
组件作为 Formik <Field />
组件的组件属性传递。
import Formik, Field, Form from 'formik';
import TextField from 'formik-material-ui';
<Field
name="email"
label="Email"
type="email"
component=TextField
/>
Formik 将继续按预期处理验证,并将呈现 Material UI 组件和错误消息。其他 Mui 输入组件的文档中有更多详细信息,并有助于自定义。
【讨论】:
【参考方案5】:在此处查看 <Field />
的 formik 文档:https://jaredpalmer.com/formik/docs/api/field
例如,您可以使用 Material 的 OutlinedInput 设置输入样式:
<Field as=OutlinedInput />
【讨论】:
【参考方案6】:要使用 material-ui 和 formik,您可以使用 formik 官方文档中的变体: https://formik.org/docs/examples/with-material-ui
【讨论】:
【参考方案7】:您可以使用setFieldValue 方法可用于创建自定义输入更改处理程序
<Formik
initialValues=
name: "",
onSubmit=(values: any) => console.log(values)
>
( handleSubmit, setFieldValue ) => (
<Form noValidate autoComplete="off" onSubmit=handleSubmit>
<TextField
onChange=(event) => setFieldValue("name", event.target.value)
type="text"
label="Name"
/>
</Form>
)
</Formik>
【讨论】:
以上是关于Formik 和 Material-UI的主要内容,如果未能解决你的问题,请参考以下文章
使用 Formik 和 Yup 和 React-select 进行验证
Formik:useField 钩子上的 onBlur 处理程序