Formik и Material-UI

Я пытаюсь использовать 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;

Я хочу, чтобы Formik отвечал за валидацию, а Material-UI - за внешний вид. Я хочу передать error.firstName компоненту TextField, но ошибка отображается некорректно. Как это исправить, чтобы все еще было ясно для чтения? Я не хочу писать свой собственный компонент TextField.

Я не знаю, как интегрировать компоненты Material-ui с валидацией Formik, но я могу порекомендовать вместо этого react-final-form, которая очень хорошо интегрируется с MUI: github.com/final-form/react-final-form#material-ui-10

Ricovitch 31.08.2018 11:56

Спасибо, но мне все еще нужно создать собственные компоненты для каждого из компонентов material-ui. Я бы предпочел не делать этого. У тебя есть идеи, как это сделать?

n3stle 31.08.2018 12:19

Это может показаться излишним, но мы обнаружили, что на самом деле просто и прямо обернуть компоненты формы material-ui, подобные этой. Я думаю, вам всегда придется каким-то образом сопоставлять свойства фреймворка FormXXX с компонентами Material-UI.

Ricovitch 31.08.2018 16:53

Вы можете посмотреть, что было сделано в этом проекте: github.com/stackworx/formik-material-ui/tree/master/src

Ricovitch 03.09.2018 17:41

Я действительно думаю, что вам следует подумать о создании пользовательских компонентов для каждого компонента Material-UI. Вот почему: не повторяйтесь (сопоставление Formik API с MUI props выполняется один раз), ограничьте влияние MUI или Formik, нарушающих изменения в будущем.

Ricovitch 03.09.2018 17:48

Через пару дней с этим. Думаю, ты прав. Спасибо! Теперь мне нужно выяснить, как сопоставить эти компоненты.

n3stle 04.09.2018 10:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
23
6
30 707
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Я не думаю, что вам нужна другая библиотека или даже создать свою собственную оболочку, я думаю, вам нужно немного подправить свой код.

Одна из ваших проблем заключается в том, что вы не передаете функцию onChange в текстовом поле материала, поэтому значение формы firstName всегда равно нулю, и вы всегда получаете сообщение об ошибке, даже если вы ввели имя. Попробуйте добавить имя или идентификатор в текстовое поле и функцию onChange следующим образом:

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

Нет, все еще не работает. Ошибка не отображается, когда поле пусто

n3stle 03.09.2018 08:35

Ошибка появляется, но в настоящее время вы настроили свои проверки, чтобы они отображались на Submit. Это означает, что вам нужно нажать Enter, чтобы он появился. Если вы хотите, чтобы они отображались также в onChange и onBlur, см. Мой обновленный ответ. Надеюсь это поможет.

needsleep 03.09.2018 09:43

Вы обнаружите, что повторяете сопоставление реквизита с реквизитами компонентов Material-UI в каждом экземпляре «Field», в этом и заключается смысл создания оболочек Material-UI для меня, и имеет смысл централизовать это сопоставление в пользовательских компонентах. Представьте себе день, когда MUI или Formik претерпят критические изменения в своих API / Props. Вам просто нужно обновить один компонент!

Ricovitch 03.09.2018 17:46

Вы правы, компонент-оболочка - хорошая идея. Но я думаю, что первое, что нужно сделать здесь, это заставить его работать в одном поле, а затем он может сосредоточиться на создании оболочек на основе того, что ему нужно построить.

needsleep 03.09.2018 22:29

Это место, куда можно пойти formik.org/docs/api/field#children

Chris Claude 09.10.2020 21:42
Ответ принят как подходящий

Как упоминалось в комментариях, на самом деле может быть хорошей идеей реализовать компоненты «оболочки», как это было в этих примерах из Formik или ReactFinalForm:

Идея та же: реализовать пользовательские компоненты «оболочки», чтобы обернуть компоненты UI и сопоставить свойства Formik или ReactFinalForm API.

Преимущества этого подхода - централизовать в одном месте сопоставление между двумя фреймворками, чтобы вы не повторяли сопоставление каждый раз, и если одна из фреймворков вносит критические изменения, вам просто нужно изменить эти пользовательские компоненты «оболочки».

Вы можете попробовать это: https://github.com/daixianceng/formik-material-fields

Монтаж:

npm install --save formik-material-fields

Использование:

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

Отличный ответ !! Спасибо

Juan 22.03.2019 08:38

Эта библиотека великолепна для специалиста по бэкенду, которому нужен быстрый и простой пользовательский интерфейс!

Justin Rice 03.09.2019 20:15

Вы также можете попробовать эту библиотеку, которая делает за вас всю тяжелую работу и реализует код оболочки для компонентов UI-материала (включая <TextField />): https://github.com/stackworx/formik-material-ui.

Монтаж:

yarn add formik-material-ui

В компоненте формы Formik передайте компонент <TextField /> в качестве свойства компонента Formik <Field />.

import { Formik, Field, Form } from 'formik';
import { TextField } from 'formik-material-ui';

<Field
  name = "email"
  label = "Email"
  type = "email"
  component = {TextField}
/>

Formik продолжит обработку проверки, как ожидалось, и отобразит компонент пользовательского интерфейса материала и сообщение об ошибке. В документации есть дополнительные сведения для других компонентов ввода Mui, а также для помощи в настройке.

Ознакомьтесь с документацией formik для <Field /> здесь: https://jaredpalmer.com/formik/docs/api/field

В качестве примера вы можете использовать OutlinedInput материала для стилизации ввода:

<Field as = {OutlinedInput} />

Чтобы использовать материал-интерфейс и Formik, вы можете использовать вариант из официальная документация formik: https://formik.org/docs/examples/with-material-ui

Вы можете использовать метод setFieldValueполезно для создания пользовательских обработчиков изменений ввода

<Formik
  initialValues = {{
    name: "",
  }}
  onSubmit = {(values: any) => console.info(values)}
>
  {({  handleSubmit, setFieldValue }) => (
    <Form noValidate autoComplete = "off" onSubmit = {handleSubmit}>
      <TextField
        onChange = {(event) => setFieldValue("name", event.target.value)} 
        type = "text"
        label = "Name"
      />
    </Form>
  )}
</Formik>

Другие вопросы по теме