javascript - Formik och Material-UI


Jag försöker använda Formik med Material-UI-textfält. Så här:

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;

Jag vill att Formik ska vara ansvarig för validering och Material-UI för utseendet. Jag vill skicka errors.firstName till TextField-komponenten men felet visas inte korrekt. Hur kan jag fixa det så att det fortfarande är tydligt att läsa? Jag vill inte skriva min egen TextField-komponent.

Svar #1

Jag tror inte att du behöver ett annat bibliotek eller ens skapa din egen wrapper, jag tror att du behöver justera din kod lite.

Ett problem du har är att du inte skickar in en onChange-funktion i Material TextField, så formulärvärdet för firstName är alltid null och därför får du alltid felet, även om du har angett ett namn. Försök att lägga till ett namn eller id på ditt TextField och en onChange-funktion så här:

<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)
        }
    />
    )}
/>

Svar #2

Som nämnts i kommentarerna kan det faktiskt vara en bra idé att implementera "wrapper"-komponenter, som de gjorde i dessa exempel från Formik eller ReactFinalForm :

  • https://github.com/stackworx/formik-material-ui/tree/master/src
  • https://github.com/final-form/react-final-form#material-ui-10

Idén är densamma: implementera egna "wrapper"-komponenter för att omsluta Material-UI-komponenter och mappa Formik- eller ReactFinalForm-API:ernas props.

Fördelarna med detta tillvägagångssätt är att centralisera kartläggningen mellan de två ramverken på ett ställe, så att du inte upprepar kartläggningen varje gång, och om ett av ramverken inför brytande förändringar behöver du bara ändra de anpassade "wrapper"-komponenterna.

Relaterade artiklar