Я пытаюсь использовать 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. Я бы предпочел не делать этого. У тебя есть идеи, как это сделать?
Это может показаться излишним, но мы обнаружили, что на самом деле просто и прямо обернуть компоненты формы material-ui, подобные этой. Я думаю, вам всегда придется каким-то образом сопоставлять свойства фреймворка FormXXX с компонентами Material-UI.
Вы можете посмотреть, что было сделано в этом проекте: github.com/stackworx/formik-material-ui/tree/master/src
Я действительно думаю, что вам следует подумать о создании пользовательских компонентов для каждого компонента Material-UI. Вот почему: не повторяйтесь (сопоставление Formik API с MUI props выполняется один раз), ограничьте влияние MUI или Formik, нарушающих изменения в будущем.
Через пару дней с этим. Думаю, ты прав. Спасибо! Теперь мне нужно выяснить, как сопоставить эти компоненты.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я не думаю, что вам нужна другая библиотека или даже создать свою собственную оболочку, я думаю, вам нужно немного подправить свой код.
Одна из ваших проблем заключается в том, что вы не передаете функцию 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)
}
/>
)}
/>
Нет, все еще не работает. Ошибка не отображается, когда поле пусто
Ошибка появляется, но в настоящее время вы настроили свои проверки, чтобы они отображались на Submit. Это означает, что вам нужно нажать Enter, чтобы он появился. Если вы хотите, чтобы они отображались также в onChange и onBlur, см. Мой обновленный ответ. Надеюсь это поможет.
Вы обнаружите, что повторяете сопоставление реквизита с реквизитами компонентов Material-UI в каждом экземпляре «Field», в этом и заключается смысл создания оболочек Material-UI для меня, и имеет смысл централизовать это сопоставление в пользовательских компонентах. Представьте себе день, когда MUI или Formik претерпят критические изменения в своих API / Props. Вам просто нужно обновить один компонент!
Вы правы, компонент-оболочка - хорошая идея. Но я думаю, что первое, что нужно сделать здесь, это заставить его работать в одном поле, а затем он может сосредоточиться на создании оболочек на основе того, что ему нужно построить.
Это место, куда можно пойти formik.org/docs/api/field#children
Как упоминалось в комментариях, на самом деле может быть хорошей идеей реализовать компоненты «оболочки», как это было в этих примерах из 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>
);
}
}
Отличный ответ !! Спасибо
Эта библиотека великолепна для специалиста по бэкенду, которому нужен быстрый и простой пользовательский интерфейс!
Вы также можете попробовать эту библиотеку, которая делает за вас всю тяжелую работу и реализует код оболочки для компонентов 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>
Я не знаю, как интегрировать компоненты Material-ui с валидацией Formik, но я могу порекомендовать вместо этого react-final-form, которая очень хорошо интегрируется с MUI: github.com/final-form/react-final-form#material-ui-10