Formik和Material-UI

n3s*_*tle 12 javascript typescript reactjs material-ui formik

我正在尝试使用Formik与Material-UI文本字段.像这样:

import TextField from '@material-ui/core/TextField';
import {
  Field,
  FieldProps,
  Form,
  Formik,
  FormikErrors,
  FormikProps
} from 'formik';
import React, { Component } from 'react';

interface IMyFormValues {
  firstName: string;
}

class CreateAgreementForm extends Component<{}> {
  public render() {
    return (
      <div>
        <h1>My Example</h1>
        <Formik
          initialValues={{ firstName: '' }}
          // tslint:disable-next-line:jsx-no-lambda
          onSubmit={(values: IMyFormValues) => alert(JSON.stringify(values))}
          // tslint:disable-next-line:jsx-no-lambda
          validate={(values: IMyFormValues) => {
            const errors: FormikErrors<IMyFormValues> = {};
            if (!values.firstName) {
              errors.firstName = 'Required';
            }
            return errors;
          }}
          // tslint:disable-next-line:jsx-no-lambda
          render={(formikBag: FormikProps<IMyFormValues>) => (
            <Form>
              <Field
                name="firstName"
                render={({ field, form }: FieldProps<IMyFormValues>) => (
                  <TextField
                    error={Boolean(
                      form.errors.firstName && form.touched.firstName
                    )}
                    helperText={
                      form.errors.firstName &&
                      form.touched.firstName &&
                      String(form.errors.firstName)
                    }
                  />
                )}
              />
            </Form>
          )}
        />
      </div>
    );
  }
}

export default CreateAgreementForm;
Run Code Online (Sandbox Code Playgroud)

我希望Formik负责验证和Material-UI的外观.我想将errors.firstName传递给TextField组件,但错误无法正确显示.如何修复它以便仍然可以阅读?我不想编写自己的TextField组件.或者也许还有一些其他流行的表格库?

Ric*_*tch 13

正如在评论中提到的那样,实现"包装器"组件实际上可能是一个好主意,就像他们在Formik或ReactFinalForm中的示例中所做的那样:

这个想法是一样的:实现自定义"包装"组件来包装Material-UI组件并映射Formik或ReactFinalForm API道具.

这种方法的优点是将两个框架之间的映射集中在一个地方,这样您就不会每次都重复映射,如果其中一个框架引入了重大更改,您只需要更改这些自定义"包装器"组件.


nee*_*eep 12

我认为您不需要其他库甚至不需要创建自己的包装器,我认为您需要花一些时间来编写代码。

您遇到的一个问题是,您没有在Material TextField中传递onChange函数,因此firstName的表单值始终为null,因此即使输入名称也始终会出错。尝试在您的TextField和onChange函数上添加名称或ID,如下所示:

<Field
    validateOnBlur
    validateOnChange
    name="firstName"
    render={({ field, form }) => (
    <TextField
        name={"firstName"}
        error={
            Boolean(form.errors.firstName && form.touched.firstName)
        }
        onChange={formikBag.handleChange}
        onBlur={formikBag.handleBlur}
        helperText={
            form.errors.firstName &&
            form.touched.firstName &&
            String(form.errors.firstName)
        }
    />
    )}
/>
Run Code Online (Sandbox Code Playgroud)

  • 您会发现自己在每个“字段”实例中都重复了props到Material-UI组件props的映射,这就是为我创建Material-UI包装器的关键所在,并且确实可以将这种映射集中在自定义组件中。想象有一天,MUI或Formik在其API /道具中发生了重大变化。您只需要更新一个组件即可! (2认同)
  • 你是对的,包装组件是个好主意。但是我认为要做的第一件事是使其在单个字段上工作,然后他可以根据自己的需要集中精力构建包装器。 (2认同)

小智 7

查看<Field />此处的 formik 文档:https://jaredpalmer.com/formik/docs/api/field

作为示例,您可以使用 Material 的 OutlinedInput 来设置输入的样式:

<Field as={OutlinedInput} />
Run Code Online (Sandbox Code Playgroud)

如果您需要将更多属性传递给 OutlinedInput,只需将它们添加到 Field,它就会将它们传递给 OutlinedInput:

<Field as={OutlinedInput} color="primary" InputProps={{ startAdornment: <InputAdornment position="start"><AccountCircle /></InputAdornment> }} />
Run Code Online (Sandbox Code Playgroud)


小智 5

您可以尝试以下方法:https : //github.com/daixianceng/formik-material-fields

安装:

npm install --save formik-material-fields
Run Code Online (Sandbox Code Playgroud)

用法:

import React, { Component } from 'react';
import { Formik, Form } from 'formik';
import * as Yup from 'yup';
import { FormikTextField } from 'formik-material-fields';

const validationSchema = Yup.object().shape({
  username: Yup.string().required(),
});

const initialValues = {
  username: '',
};

class MyForm extends Component {
  render() {
    return (
      <Formik
        initialValues={initialValues}
        validationSchema={validationSchema}
        onSubmit={this.props.onSubmit}
      >
        {({ isValid }) => (
          <Form autoComplete="off">
            <FormikTextField
              name="username"
              label="Username"
              margin="normal"
              fullWidth
            />
          </Form>
        )}
      </Formik>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)