Formik 表单中的某些字段未更新

时间:2021-06-28 21:46:21

标签: javascript reactjs typescript material-ui

对于 Material-UI 字段,我有一个特殊的 TextField 包装器,它似乎运行良好。出于某种原因,当我使用原生 Material UI 字段时,它们不会在提交时更新表单数据。

这是相关的代码(但我在帖子末尾添加了一个代码沙箱以帮助演示该问题)

TestForm.tsx

import { Card, CardActions, CardContent } from "@material-ui/core";
import { Form, Formik, Field } from "formik";
import React from "react";
import SubmitButton from "../../SubmitButton";
import CancelButton from "../../CancelButton";
import TextField from "../../TextField";
import MuiTextField from "@material-ui/core/TextField";

interface TestFormProps {
  onSave: (fields: FormFields) => void;
  onCancel: () => void;
}

export interface FormFields {
  textField: string;
  numericField: number;
  materialField: string;
  materialFieldFromComponent: string;
}

const initialValues: FormFields = {
  textField: "Default Text",
  numericField: 42,
  materialField: "Default Mui",
  materialFieldFromComponent: "Default Mui from Component"
};

const TestForm: React.FC<TestFormProps> = ({ onCancel, onSave }) => {
  return (
    <Formik
      initialValues={initialValues}
      onSubmit={async (fields, { setSubmitting }) => {
        setSubmitting(true);
        onSave(fields);
      }}
    >
      {({ isSubmitting }) => (
        <Form>
          <Card>
            <CardContent>
              <TextField name="textField" label="Text field" />
              <TextField
                name="numericField"
                type="number"
                label="Numeric field"
              />
              <div>
                <MuiTextField
                  name="materialField"
                  label="Mui field"
                  variant="outlined"
                  margin="dense"
                />
              </div>
              <Field
                name="materialFieldFromComponent"
                label="Mui field from Component"
                variant="outlined"
                margin="dense"
                component={MuiTextField}
              />
            </CardContent>
            <CardActions>
              <SubmitButton disabled={isSubmitting} />
              <CancelButton onCancel={onCancel} />
            </CardActions>
          </Card>
        </Form>
      )}
    </Formik>
  );
};

export default TestForm;

TextField.tsx

import React from "react";
import { FieldAttributes, useField } from "formik";
import {
  InputBaseComponentProps,
  TextField as MuiTextField
} from "@material-ui/core";

interface TextFieldProps {
  label: string;
  inline?: boolean;
  inputProps?: InputBaseComponentProps;
}

const Field: React.FC<FieldAttributes<TextFieldProps>> = (props) => {
  const { type, label, placeholder, inputProps } = props;
  const [field, meta] = useField<TextFieldProps>(props);
  const errorText = meta.error && meta.touched ? meta.error : "";

  return (
    <MuiTextField
      {...field}
      label={label}
      variant="outlined"
      margin="dense"
      type={type}
      placeholder={placeholder ? placeholder : label}
      helperText={errorText}
      error={!!errorText}
      inputProps={inputProps}
    />
  );
};

const TextField: React.FC<FieldAttributes<TextFieldProps>> = ({
  inline = false,
  ...props
}) => {
  return inline ? (
    <Field {...props} />
  ) : (
    <div>
      <Field {...props} />
    </div>
  );
};

export default TextField;

这是代码沙箱:

https://codesandbox.io/s/recursing-northcutt-5deen

1 个答案:

答案 0 :(得分:1)

这是因为您创建的 TextField 传递了正确的字段属性,而材质 UI 字段的其他直接实现则没有。

按如下方式传递正确的属性,即可解决问题:

    {({ isSubmitting, handleChange, handleBlur, values }) => (
              ...
              <div>
                <MuiTextField
                  name="materialField"
                  label="Mui field"
                  variant="outlined"
                  margin="dense"
                  onChange={handleChange}
                  onBlur={handleBlur}
                  value={values.materialField}
                />
              </div>
              <Field
                name="materialFieldFromComponent"
                label="Mui field from Component"
                variant="outlined"
                margin="dense"
                render={({ field }) => <MuiTextField {...field} />}
              />
         ...

MuiTextField 现在在其属性上传递了 onChangevalues,从而正确更新了值。

完整代码:TestForm.tsx

import { Card, CardActions, CardContent } from "@material-ui/core";
import { Form, Formik, Field } from "formik";
import React from "react";
import SubmitButton from "../../SubmitButton";
import CancelButton from "../../CancelButton";
import TextField from "../../TextField";
import MuiTextField from "@material-ui/core/TextField";

interface TestFormProps {
  onSave: (fields: FormFields) => void;
  onCancel: () => void;
}

export interface FormFields {
  textField: string;
  numericField: number;
  materialField: string;
  materialFieldFromComponent: string;
}

const initialValues: FormFields = {
  textField: "Default Text",
  numericField: 42,
  materialField: "Default Mui",
  materialFieldFromComponent: "Default Mui from Component"
};

const TestForm: React.FC<TestFormProps> = ({ onCancel, onSave }) => {
  return (
    <Formik
      initialValues={initialValues}
      onSubmit={async (fields, { setSubmitting }) => {
        setSubmitting(true);
        onSave(fields);
      }}
    >
      {({ isSubmitting, handleChange, handleBlur, values }) => (
        <Form>
          <Card>
            <CardContent>
              <TextField name="textField" label="Text field" />
              <TextField
                name="numericField"
                type="number"
                label="Numeric field"
              />
              <div>
                <MuiTextField
                  name="materialField"
                  label="Mui field"
                  variant="outlined"
                  margin="dense"
                  onChange={handleChange}
                  onBlur={handleBlur}
                  value={values.materialField}
                />
              </div>
              <Field
                name="materialFieldFromComponent"
                label="Mui field from Component"
                variant="outlined"
                margin="dense"
                render={({ field }) => <MuiTextField {...field} />}
              />
            </CardContent>
            <CardActions>
              <SubmitButton disabled={isSubmitting} />
              <CancelButton onCancel={onCancel} />
            </CardActions>
          </Card>
        </Form>
      )}
    </Formik>
  );
};

export default TestForm;