映射 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.bindthat (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 函数对字段进行迭代。

首先分离出独特的领域道具

  1. 属于输入的道具,如nameidlabel
  2. 属于组件的道具,如variantmarginhandlers

您最终会得到 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 辅助函数以通过类型检查问题。