【问题标题】:Map Formik Text-Fields映射 Formik 文本字段
【发布时间】:2020-03-28 15:31:15
【问题描述】:

我正在使用材料 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)

【问题讨论】:

  • 也许你想看看 Formik 新的 useFormik 钩子。更简洁的语法
  • 您是否成功地映射了您的字段?您也有注释代码的问题,您映射了道具但您从未设置它们
  • 如果你能在代码中重现这个问题,我会尽力帮助你
  • @Sabbin 你好,给你:codesandbox.io/s/green-fog-38yqe?file=/src/App.tsxTHANKSS
  • @Jnl 我在下面的答案中添加了解决方案和解释,请查看

标签: javascript reactjs typescript material-ui formik


【解决方案1】:

感谢您提供沙盒。

根据您的沙箱,我已设法通过 map 函数进行字段迭代。

先分离唯一字段props

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

你最终会得到 2 个对象。

(1)一个应该抽象到组件并保存在单独文件中的字段,您以后可以使用另一个组件中的字段。

这里因为你使用了formik,而且你需要有一个formik的引用键,所以我在对象中添加了formikRef

const fileds = [
  {
    id: "email",
    name: "email",
    formikRef: "email",
    label: "Email"
  },

  {
    id: "name",
    name: "name",
    formikRef: "name",
    label: "Name"
  }
];

(2) 应该存储在组件中的第二个对象,因为它解析了&lt;TextField/&gt; 道具

我通常将它们包装在 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 辅助函数,以便通过类型检查问题。

【讨论】:

  • 代码沙箱在formik.touched[formikRef]等上给出了一些类型错误。虽然它似乎在沙箱上工作,但它不会在VS上离线编译。
  • 沙盒中的类型错误在哪里?我什么都没有,甚至在沙盒中都没有警告......我怎么知道你在 VS 中有什么?我根据您在沙箱中提供的代码提供了答案。
  • 这很奇怪。我在qs中附上了截图。打开沙箱时出现这些错误。关于 VS 代码,我的意思是 idk 这是如何在这里编译的,它在 VS 上不起作用,就像我在代码沙箱之外实现它一样。因为我遇到了这些错误
  • @Jnl 我已经更新了答案和沙盒,请检查
  • 很抱歉,由于Textfield 的重载错误,它仍然不适合我:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-28
  • 1970-01-01
  • 2020-04-17
  • 2016-07-10
  • 1970-01-01
  • 2021-08-22
  • 1970-01-01
相关资源
最近更新 更多