映射 Formik 文本字段
Map Formik Text-Fields
我正在使用 material ui 文本字段并使用 Formik 验证它们。我不想多次输入所有内容,而是想映射项目,但我无法这样做。
return (
<div>
<Formik
initialValues={{ email: '' }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
validationSchema={schema}>
{props => {
const {
values: { email },
errors,
touched,
handleChange,
isValid,
setFieldTouched,
} = props;
const change = (name: string, e: FormEvent) => {
e.persist();
handleChange(e);
setFieldTouched(name, true, false);
};
return (
<div className="main-content">
<form
style={{ width: '100%' }}
onSubmit={e => {
e.preventDefault();
submitForm(email);
}}>
<div>
<TextField
variant="outlined"
margin="normal"
id="email"
name="email"
helperText={touched.email ? errors.email : ''}
error={touched.email && Boolean(errors.email)}
label="Email"
value={email}
onChange={change.bind(null, 'email')}
/>
{/* {[{ variant:"outlined", margin:"normal", id:"email", name:"email", label: "Email", value: email, onChange:{change.bind(null, 'email')}
].map((item, index) => (
<TextField></TextField>
))} */}
<br></br>
<CustomButton
text={'Remove User'}
/>
</div>
</form>
</div>
);
}}
</Formik>
</div>
);
目前在注释掉的部分,我在 change.bind
that (property) change: (name: string, e: React.FormEvent<Element>) => void
',' expected.ts(1005)
上收到错误
同样,如果我尝试在要映射到文本字段的参数列表中添加 helperText:{touched.email ? errors.email : ''}
,我会得到:
(property) touched: FormikTouched<{
email: string;
}>
',' expected.ts(1005)
于 touched.email
。当我尝试使用 errors.
时也是如此
(property) touched: FormikTouched<{
email: string;
}>
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'FormikTouched<{ email: string; }>'.
No index signature with a parameter of type 'string' was found on type 'FormikTouched<{ email: string; }>'.ts(7053)
感谢您提供沙盒。
基于您的沙箱,我已经设法通过 map
函数对字段进行迭代。
首先分离出独特的领域道具
- 属于输入的道具,如
name
id
label
等
- 属于组件的道具,如
variant
margin
handlers
等
您最终会得到 2 个对象。
(1)应该抽象到组件中,保存在一个单独的文件中,以后可能会在其他组件中使用这些字段。
这里因为你用的是formik,需要有一个formik的reference key,所以我在对象里加了formikRef
const fileds = [
{
id: "email",
name: "email",
formikRef: "email",
label: "Email"
},
{
id: "name",
name: "name",
formikRef: "name",
label: "Name"
}
];
(2) 应该存储在组件中的第二个对象,因为它解析了 <TextField/>
props
我通常将它们包装在 useMemo 钩子中,因此如果依赖对象未更改,则不应重新声明。这只是为了性能,您也可以使用直接对象
const defaultProps = React.useMemo(() => ({
textField: {
variant: 'outlined',
margin: 'normal',
onChange: props => {
formik.handleChange(props);
formik.handleBlur(props);
},
onBlur: formik.handleBlur
}
}),
[formik]
);
//without useMemo
const defaultProps = {
textField: {
variant: 'outlined',
margin: 'normal',
onChange: props => {
formik.handleChange(props);
formik.handleBlur(props);
},
onBlur: formik.handleBlur
}
}
最后一步是在渲染中映射道具
{
fileds.map(({ formikRef, ...input }) => (
<TextField
key={formikRef}
helperText={getIn(formik.touched, formikRef) ? getIn(formik.errors, formikRef) : ''}
error={getIn(formik.touched, formikRef) && Boolean(getIn(formik.errors, formikRef))}
value={getIn(formik.values, formikRef)}
{...input}
{...defaultProps.textField}
/>
))
}
我还创建了一个工作沙箱 HERE
LE: 类型检查是个问题,但可以通过一些搜索找到解决方案...已讨论 here
我已经进行了更正并从 Formik
添加了 getIn
辅助函数以通过类型检查问题。
我正在使用 material ui 文本字段并使用 Formik 验证它们。我不想多次输入所有内容,而是想映射项目,但我无法这样做。
return (
<div>
<Formik
initialValues={{ email: '' }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
validationSchema={schema}>
{props => {
const {
values: { email },
errors,
touched,
handleChange,
isValid,
setFieldTouched,
} = props;
const change = (name: string, e: FormEvent) => {
e.persist();
handleChange(e);
setFieldTouched(name, true, false);
};
return (
<div className="main-content">
<form
style={{ width: '100%' }}
onSubmit={e => {
e.preventDefault();
submitForm(email);
}}>
<div>
<TextField
variant="outlined"
margin="normal"
id="email"
name="email"
helperText={touched.email ? errors.email : ''}
error={touched.email && Boolean(errors.email)}
label="Email"
value={email}
onChange={change.bind(null, 'email')}
/>
{/* {[{ variant:"outlined", margin:"normal", id:"email", name:"email", label: "Email", value: email, onChange:{change.bind(null, 'email')}
].map((item, index) => (
<TextField></TextField>
))} */}
<br></br>
<CustomButton
text={'Remove User'}
/>
</div>
</form>
</div>
);
}}
</Formik>
</div>
);
目前在注释掉的部分,我在 change.bind
that (property) change: (name: string, e: React.FormEvent<Element>) => void
',' expected.ts(1005)
同样,如果我尝试在要映射到文本字段的参数列表中添加 helperText:{touched.email ? errors.email : ''}
,我会得到:
(property) touched: FormikTouched<{
email: string;
}>
',' expected.ts(1005)
于 touched.email
。当我尝试使用 errors.
(property) touched: FormikTouched<{
email: string;
}>
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'FormikTouched<{ email: string; }>'.
No index signature with a parameter of type 'string' was found on type 'FormikTouched<{ email: string; }>'.ts(7053)
感谢您提供沙盒。
基于您的沙箱,我已经设法通过 map
函数对字段进行迭代。
首先分离出独特的领域道具
- 属于输入的道具,如
name
id
label
等 - 属于组件的道具,如
variant
margin
handlers
等
您最终会得到 2 个对象。
(1)应该抽象到组件中,保存在一个单独的文件中,以后可能会在其他组件中使用这些字段。
这里因为你用的是formik,需要有一个formik的reference key,所以我在对象里加了formikRef
const fileds = [
{
id: "email",
name: "email",
formikRef: "email",
label: "Email"
},
{
id: "name",
name: "name",
formikRef: "name",
label: "Name"
}
];
(2) 应该存储在组件中的第二个对象,因为它解析了 <TextField/>
props
我通常将它们包装在 useMemo 钩子中,因此如果依赖对象未更改,则不应重新声明。这只是为了性能,您也可以使用直接对象
const defaultProps = React.useMemo(() => ({
textField: {
variant: 'outlined',
margin: 'normal',
onChange: props => {
formik.handleChange(props);
formik.handleBlur(props);
},
onBlur: formik.handleBlur
}
}),
[formik]
);
//without useMemo
const defaultProps = {
textField: {
variant: 'outlined',
margin: 'normal',
onChange: props => {
formik.handleChange(props);
formik.handleBlur(props);
},
onBlur: formik.handleBlur
}
}
最后一步是在渲染中映射道具
{
fileds.map(({ formikRef, ...input }) => (
<TextField
key={formikRef}
helperText={getIn(formik.touched, formikRef) ? getIn(formik.errors, formikRef) : ''}
error={getIn(formik.touched, formikRef) && Boolean(getIn(formik.errors, formikRef))}
value={getIn(formik.values, formikRef)}
{...input}
{...defaultProps.textField}
/>
))
}
我还创建了一个工作沙箱 HERE
LE: 类型检查是个问题,但可以通过一些搜索找到解决方案...已讨论 here
我已经进行了更正并从 Formik
添加了 getIn
辅助函数以通过类型检查问题。