#typescript #material-ui #react-hook-form
#typescript #материал-пользовательский интерфейс #форма с реагирующими крючками
Вопрос:
Я пытаюсь использовать React с Material UI и react-hook-form и yup для проверки. Я совершенно новичок во всех частях этого списка. Я хотел бы настроить очень простую форму входа в систему, используя хорошо известную страницу входа в Material UI и Typescript.
На данный момент у меня очень простая проверка, применяется только «обязательное» правило. Я ожидаю, что когда я нажму «Отправить», не заполняя форму, я бы хотел увидеть сообщение об ошибке под вводом, которое должно стать красным. Точно так же, как в примерах, показанных на официальной странице пользовательского интерфейса Material. И здесь возникает проблема… Когда я нажимаю «Отправить», не заполняя форму, фокус переходит на первое поле с ошибкой, и на странице появляется всплывающая подсказка, но не под компонентом, она больше похожа на «плавающий пузырь», а контур не становится красным. (Даже сообщение об ошибке в плавающем пузырьке является чем-то общим, а не тем, что я установил в yup для отображения.)
Я также попытался оставить yup вне проекта и просто использовать атрибут rules, но это привело к тому же. вещи.
Итак, вот компоненты, которые я использую. Извините, если это займет слишком много времени, я еще не выделил место для хранения для этого проекта:
import Button from '@material-ui/core/Button';
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import { FormTextField } from '@tao-ui-shared/form';
import React from 'react';
import { FormProvider } from 'react-hook-form';
import { getLogger } from '../../logging/authenticationLogging';
import { useLoginForm } from '../hooks/useLoginForm';
import { useStyles } from './login.styles';
type LoginFormParams = {
name?: string;
classes?: Record<'submit' | 'form', string>
}
export const LoginForm: React.FC<LoginFormParams> = ({
name
}) => {
// eslint-disable-next-line @typescript-eslint/unbound-method
const { register, onSubmit, errors, ...methods } = useLoginForm();
return (
<FormProvider register={register} errors={errors} {...methods} >
<form onSubmit={onSubmit}>
<FormTextField
name='email'
id='email'
variant='outlined'
autoComplete='email'
label='Email'
required
autoFocus
errors={errors}
/>
<FormTextField
name='password'
id='password'
variant='outlined'
required
fullWidth
label='Password'
type='password'
autoComplete='current-password'
errors={errors}
/>
<Button
type="submit"
fullWidth variant="contained"
color="primary"
>
Login
</Button>
</form>
</FormProvider>
);
}
import { FormControl, TextField } from '@material-ui/core';
import React, { useEffect, useRef } from 'react';
import { Controller } from 'react-hook-form';
export type FormTextFieldParams = {
readonly name: string;
readonly id: string;
readonly variant: 'standard' | 'filled' | 'outlined' | undefined;
readonly defaultValue?: string;
readonly label?: string;
readonly margin?: 'normal' | 'none' | 'dense' | undefined;
readonly autoComplete?: string;
readonly type?: string;
readonly disabled?: boolean;
readonly required?: boolean;
readonly fullWidth?: boolean;
readonly autoFocus?: boolean;
readonly minLength?: number;
readonly maxLength?: number;
readonly errors?: any;
};
export const FormTextField: React.FC<FormTextFieldParams> = ({
id,
name,
errors,
variant = 'standard',
margin = 'normal',
label = '',
type = '',
disabled = false,
required = false,
fullWidth = true,
autoFocus = false,
autoComplete= ''
}) => {
const isError = useRef(false);
const errorMessage = useRef('');
useEffect(() => {
Object.prototype.hasOwnProperty.call(errors, name);
if (errors amp;amp; Object.prototype.hasOwnProperty.call(errors, name)) {
isError.current = true;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
errorMessage.current = errors[name].message;
}
}, [errors, name]);
return (
<FormControl fullWidth={fullWidth}>
<Controller
as={TextField}
id={id}
name={name}
variant={variant}
margin={margin}
label={label}
type={type}
required={required}
fullWidth={fullWidth}
autoFocus={autoFocus}
autoComplete={autoComplete}
error={isError.current}
helperText={errorMessage.current}
disabled={disabled}
/>
</FormControl>
);
};
import { yupResolver } from '@hookform/resolvers';
import { login } from '@tao-ui-shared/authentication-service'
import { useCallback, useMemo } from 'react';
import { useForm } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import * as yup from 'yup';
import { LoginFormData } from '../../types';
export const useLoginForm = () => {
const validationSchema = useMemo(() => (
yup.object().shape({
email: yup.string().required('Username/email is required'),
password: yup.string().required('Password is required')
})
), []);
const methods = useForm<LoginFormData>({
resolver: yupResolver(validationSchema)
});
const dispatch = useDispatch();
const onSubmit = useCallback((formValues: LoginFormData) => {
// Do some logging here and dispatch and action...
}, []);
return {
...methods,
onSubmit: methods.handleSubmit(onSubmit)
}
}
Любые идеи, что я делаю не так, были бы очень признательны!
Обновить:
Я немного поиграл с этим.И, вероятно, каким-то образом мне нужно, чтобы мой компонент поля формы обертывания был повторно отображен, потому что этого не происходит, когда проверка завершается неудачей… Может ли это быть проблемой?
Комментарии:
1. Я не знаком с формой react-hook, но я уверен, что вам нужно будет передать конкретное поле
errors
объекта в поля ввода. Поскольку вы «новичок в этом», вы можете захотеть взглянуть на rff-mui , поскольку он глубоко и хорошо интегрируется с material-ui и yup2. @japrescott: Спасибо за предложение. Да, я посмотрел на final form, потому что это то, что мы используем на моем рабочем месте. Я только что перешел из бэкэнда в full stack, и я все еще не знаю этот мир React настолько глубоко, как я ожидал от себя. Но я это понимаю, и я также видел и читал некоторые узкие места окончательной формы. Особенно, когда у вас много полей формы на экране, например, с многостраничными формами. В этом приложении, над которым я сейчас работаю, если мне удастся пройти страницу входа в систему :-), это будет сценарий. Множество полей в многостраничной форме.
3. finalform позволяет вам очень хорошо контролировать, когда что следует повторно использовать с
subscription
помощью prop.