如何在 formik 字段上动态访问嵌套的 errors/touched

How to dynamically access nested errors/touched on formik Field

我正在尝试创建一个 React 组件来抽象化为我的表单创建一个输入组。所有输入都有相同的布局 - 一个标签,下面是输入,如果存在 errors/info 文本,这些文本将显示在输入下方。

之前我处理的是我自己的表格state/handlers。现在我正在尝试使用 formik(使用 Yup 验证)并且在我有嵌套信息时 运行 遇到动态访问 errortouched 字段的问题。

这是我的输入组组件:

import React from 'react';
import { FormGroup, Label, Input, FormFeedback, FormText } from 'reactstrap';
import { Field, ErrorMessage } from 'formik';

const InputGroup = ({ name, label, type, info, required }) => {
  return (
    <FormGroup>
      <Label htmlFor={name}>{label}{required && '*'}</Label>
      <Field name={name}>
        {({field, form}) => (
          <Input {...field} id={name} type={
                 invalid={form.errors[name] && form.touched[name]} //problem here
          />
        )}
      </Field>
      {info && <FormText color="muted">{info}</FormText>}
      <ErrorMessage name={name}>
          {msg => <FormFeedback>{msg}</FormFeedback>}
      </ErrorMessage>
    </FormGroup>
  )
}

InputGroup.propTypes = {
  label: PropTypes.string,
  name: PropTypes.string.isRequired,
  type: PropTypes.string,
  info: PropTypes.string,
  required: PropTypes.bool
};

InputGroup.defaultProps = {
  type: 'text',
  required: false
};

由于我使用的是 bootstrap (reactstrap@7.x),<FormFeedback> 元素需要随附的 <Input> 标记 invalid 标签.在上面,如果 formik 的 form.errors 对象上的相应字段存在(即存在错误)并且 form.touched 对象为真(即用户触摸了输入),我动态分配 invalid=true/false .

当 formik 设置为平坦的初始值(例如下面)时,这工作正常,因为 invalid={form.errors[name] && form.touched[name]} 评估为(例如)invalid={form.errors[firstName] && form.touched[firstName]}

initialValues = {
  firstName: '',
  lastName: '',
  email: '',
  password: ''
}

但是,当使用嵌套的 initialValues(例如下面)设置 formik 时, invalid={form.errors[name] && form.touched[name]} 的计算结果为 invalid={form.errors[name.first] && form.touched[name.first]}。最终,这将始终评估为 false,因此输入始终为 invalid=false,因此输入永远不会标记错误样式或显示错误消息。

initialValues = {
  name: {
    first: '',
    last: ''
  },
  email: '',
  password: ''
}

如何设置我的 InputGroup 组件,以便我可以动态访问 formik 的错误和触摸对象的必填字段,无论它是平面的还是嵌套的?

Formik 有一个函数 getIn() 可以通过路径从对象中提取值(例如,路径类似于 name.first)。

<Field name={name}>
  {({ field, form }) => (
    <Input
      {...field}
      id={name}
      invalid={getIn(form.errors, name) && getIn(form.touched, name)}
    />
  )}
</Field>

在 CodeSandbox 上看到 example here

Formik 还支持来自 Field 组件的 meta 参数,有为确切字段指定的信息(valuetouchederror) .

const CustomFormikInput = (props) => {   
    return <Field name={props.name}>
       {({ field, meta }) => {
            console.log(JSON.stringify(meta)); // Log meta output
            const errorMsg = meta.touched ? meta.error : undefined;
            return <div>
                     <input {...field} {...props} />
                     {errorMsg}
                   </div>;
        }}
    </Field>;
}