Есть страницы входа и регистрации. Код у них похожий. Использую Next.js 13v , react-hook-form, yup и функцию SWR. Проверка Yup была с самого начала написания кода и работала нормально. После того, как стала использовать функцию SWR, страница Входа при ошибке (в пароле или email) начинает постоянно перезагружается (даже не дает ввести данные). Если вводить данные пользователя без ошибок, то все хорошо. И заканчивается эта перезагрузка только после правильного заполнения поля.
Страница регистрации работает нормально, без перезагрузок , хоть с ошибками заполнено поле, хоть без ошибок.
Посмотреть можно по адресу
https://rem-ur.ru/login
Код страницы Входа:
"use client";
import Form from "@/components/Form/Form";
import styles from "@/components/Form/Form.module.scss";
import Link from "next/link";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import React, { useState } from "react";
import * as yup from "yup";
import { useRouter } from "next/navigation";
import { apiLogin } from "@/services/login";
import { useSWRConfig } from "swr";
import { baseApi } from "@/utils/constants";
const mailRegExp = /^[a-zA-z0-9-._]+@[a-z0-9-_]+\.[a-z0-9-_]{2,6}/ui;
const schema = yup.object().shape( {
email: yup
.string()
.required( "Пожалуйста, заполните это поле" )
.matches( mailRegExp, "Неправильно заполнен email" ),
password: yup
.string()
.required( "Пожалуйста, заполните это поле" )
.min( 7, "В этом поле должно быть не менее 7-ми символов" )
.max( 35, "В этом поле должно быть не более 35-х символов" ),
} );
export default async function LoginPage() {
const router = useRouter();
const { mutate } = useSWRConfig();
const { register, handleSubmit, formState: { errors } } = useForm( {
resolver: yupResolver( schema ),
mode: "onTouched",
} );
const formFields = [
{
type: "email",
name: "email",
placeholder: "mail@mail.ru",
label: "Эл. почта или телефон",
required: true,
},
{
type: "password",
name: "password",
placeholder: "dwe3jfg6Htd",
label: "Пароль",
required: true,
},
];
const onError = (errors, e) => console.log( errors, e );
const onSubmit = async(data) => {
await apiLogin( data );
await mutate(`${ baseApi }getuser`);
router.push( "/" );
}
return (
<>
<section className="section">
<h1 className="title">Вход для зарегистрированных пользователей</h1>
<Form
formFields={ formFields }
register={ register }
errors={ errors }
handleSubmit={ handleSubmit }
onSubmit={ onSubmit }
onError={ onError }
error={ error }
/>
<p className={ styles[ "login__text" ] }>Не зарегистрированы?</p>
<Link href="/registration" className="link">Зарегистрироваться</Link>
</section>
</>
);
};
Код страницы регистрации:
"use client";
import Form from "@/components/Form/Form";
import React, { useState, useEffect } from "react";
import styles from "@/components/Form/Form.module.scss";
import Link from "next/link";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { useRouter } from "next/navigation";
import { baseApi } from "@/utils/constants";
import { useRegions } from "@/services/getRegions";
import { apiRegistration } from "@/services/registration";
import { useSWRConfig } from "swr";
const nameRegExp = /[a-zA-zа-яА-яёЁ]$/;
const mailRegExp = /^[a-zA-z0-9-._]+@[a-z0-9-_]+\.[a-z0-9-_]{2,6}/ui;
const schema = yup.object().shape( {
name: yup
.string()
.required( "Пожалуйста, заполните это поле" )
.matches( nameRegExp, "Допускаются только латинские или кириллические буквы" )
.min( 2, "В этом поле должно быть не менее 2-х символов" )
.max( 20, "В этом поле должно быть не более 20-ти символа" ),
phone: yup
.string()
.required( "Пожалуйста, заполните это поле" )
.min( 17, "В этом поле должно быть не менее 11-ти символов" ),
email: yup
.string()
.when( "email", {
is: (email) => email?.length > 0,
then: () => yup.string().matches( mailRegExp, "Неправильно заполнено поле Email" ),
} ),
consent: yup
.bool()
.oneOf( [ true ], "Пожалуйста, отметьте это поле" ),
region: yup
.string()
.notOneOf( [ "" ], "Это поле не должно быть пустым" )
.required( "Пожалуйста, выберите подходящее значение" ),
password: yup
.string()
.required( "Пожалуйста, заполните это поле" )
.min( 7, "В этом поле должно быть не менее 7-ми символов" )
.max( 35, "В этом поле должно быть не более 35-х символов" ),
confirmPassword: yup
.string()
.required( "Пожалуйста, заполните это поле" )
.oneOf( [ yup.ref( "password" ), null ], "Значение этого поля должно совпадать со значением поля 'Пароль'" )
},
[ [ "email", "email" ], [ "area", "area" ] ]
);
export default function RegistrationPage() {
const { register, handleSubmit, setValue, getValues, formState: { errors, } } = useForm( {
resolver: yupResolver( schema ),
mode: "onTouched",
} );
const { regions, isError, isLoading } = useRegions();
const [ isMessageSent, setMessageSent ] = useState( false );
const [ regionId, setRegionId ] = useState();
const [ areas, setAreas ] = useState( [] );
const [ areaId, setAreaId ] = useState( "" );
const [ data, setData ] = useState( {} );
const [ formFields, setFormFields ] = useState( [] );
const [ textValue, setTextValue ] = useState( "" );
const phoneMask = "+7(999) 999-99-99";
const router = useRouter();
const { mutate } = useSWRConfig();
const breadcrumbsItems = [
{
title: "Регистрация",
url: "/registration"
}
];
useEffect( () => {
setFormFields( [
{
type: "text",
name: "name",
placeholder: "Иван",
label: "Имя",
required: true,
},
{
type: "phone",
name: "phone",
placeholder: "+7(927)568-14-52",
label: "Телефон",
required: true,
},
{
type: "email",
name: "email",
placeholder: "mail@mail.ru",
label: "Эл. почта",
required: false,
},
{
type: "select",
name: "region",
label: "Выберите регион",
options: regions,
required: true,
},
{
type: "password",
name: "password",
placeholder: "dwe3jfg6Htd",
label: "Придумайте пароль",
required: true,
},
{
type: "password",
name: "confirmPassword",
placeholder: "dwe3jfg6Htd",
label: "Повторите пароль",
required: true,
},
{
type: "mandatoryCheckbox",
name: "consent",
placeholder: " ",
label: "Даю согласие на обработку моих персональных данных",
required: true,
},
] );
}, [ regions ] );
const onSubmit = async(data) => {
const regData = {
"name": data.name,
"teleph": data.phone,
"email": data.email,
"regionId": regionId,
"areaId": areaId,
"password": data.password,
"confirmPassword": data.confirmPassword
};
try {
await apiRegistration( regData );
await mutate(`${ baseApi }getuser`);
router.push( "/" );
} catch( err ) {
console.error( err );
}
};
const onError = (errors, e) => console.log( errors, e );
const handleChangeSelect = (e, name) => {
setValue( name, e.target.value, { shouldValidate: true } );
setData( getValues() );
const getRegionAndAreaId = () => {
if( name === "region" ) {
let regId = regions.find( item => item.title === e.target.value )?.id;
return setRegionId( regId );
} else {
const areaId = areas.find( item => item.title === e.target.value )?.id;
return setAreaId( areaId );
}
};
getRegionAndAreaId();
};
useEffect( () => {
const getAreas = async() => {
const data = await fetch( `${ baseApi }api/areas/${ regionId }` );
const newAreas = await data.json();
setAreas( newAreas );
};
getAreas();
}, [ regionId ] );
useEffect( () => {
setFormFields( formFields => formFields.filter( item => {
return item.name !== "area";
} ) );
if( areas.length > 0 ) {
setFormFields( formFields => formFields.flatMap( item => {
if( item.name === "region" ) {
return [
item,
{type: "select",
name: "area",
label: "Выберите район или город",
options: areas,
required: false, },
];
}
return item;
} ) );
}
}, [ areas, regions ] );
if( isError ) return alert( "Ошибка получения регионов" );
if( isLoading ) return (
<>
<div>Подождите, загружаем форму</div>
</>
);
return (
<>
<section className="section">
<h1 className="title">Регистрация</h1>
<Form
formFields={ formFields }
register={ register }
errors={ errors }
handleSubmit={ handleSubmit }
onSubmit={ onSubmit }
onError={ onError }
handleChangeSelect={ handleChangeSelect }
isMessageSent={ isMessageSent }
messageText="Ваши данные успешно отправлены"
data={ data }
phoneMask={ phoneMask }
/>
<p className={ styles[ "login__text" ] }>Уже зарегистрированы?</p>
<Link href="/login" className="link">Войти</Link>
</section>
</>
);
}
Подскажите, пожалуйста, в чем ошибка? Что не так в коде страницы входа?