skip to Main Content

This is my login page (I use Next.js 14) below.

when setSubmitting true – loading spinner render on the page, but for some reason before page actually routes to / home page isSubmitting became false and form again shows for a second before routing.

"use client";
import UnderlinedInput from "@/components/underlined-input";
import { Button, cn } from "@nextui-org/react";
import { FormikHelpers, useFormik } from "formik";
import { useRouter } from "next/navigation";
import { object, string } from "yup";
import Link from "next/link";
import { useAppDispatch } from "@/hooks/store";
import { loginUser } from "@/store/auth/authSlice";
import LoadingSpinner from "@/components/loading-spinner";

interface InitialValues {
  email: string;
  password: string;
}

const validationSchema = object({
  email: string().email().required("email is required"),
  password: string().min(5).max(20).required("password is required"),
});

const Login = () => {
  const router = useRouter();
  const dispatch = useAppDispatch();

  const {
    errors,
    values,
    handleSubmit,
    handleChange,
    handleBlur,
    isSubmitting,
    touched,
  } = useFormik<InitialValues>({
    initialValues: {
      email: "",
      password: "",
    },
    validationSchema,
    onSubmit: onSubmit,
  });

  async function onSubmit(
    values: InitialValues,
    { setSubmitting, resetForm, setErrors }: FormikHelpers<InitialValues>
  ) {
    try {
      setSubmitting(true);
      await dispatch(loginUser(values)).unwrap();
      router.push("/");

    } catch (error) {
      console.log(error);
      setErrors({
        email: "invalid email or password",
        password: "invalid email or password",
      });
    } finally {
      setSubmitting(false);
    }
  }

  if (isSubmitting) {
    return <LoadingSpinner />;
  }

  return (
    <div>
        //form structure
    </div>
  );
};

export default Login;

ps:
I was trying use simple Promise with timeout instead of dispatching async thunk but problem is not in it

2

Answers


  1. You’ll need to await on the line where you’re using router.push("/"). The reason is due to the asynchronous nature of router.push("/"). When the setSubmitting(false) line is executed, the isSubmitting becomes false, and the form is shown again before the navigation completes.

    async function onSubmit(
      values: InitialValues,
      { setSubmitting, resetForm, setErrors }: FormikHelpers<InitialValues>
    ) {
      try {
        setSubmitting(true);
        await dispatch(loginUser(values)).unwrap();
        await router.push("/"); // <--- await here
      } catch (error) {
        console.log(error);
        // ...rest of code
    
    Login or Signup to reply.
  2. You should wait for the dispatch(loginUser(values)).unwrap() to complete before setting isSubmitting to false, By using await before the dispatch call, you ensure that the setSubmitting(false) is only executed after the dispatch operation is complete.:-

    async function onSubmit(
      values: InitialValues,
      { setSubmitting, resetForm, setErrors }: FormikHelpers<InitialValues>
    ) {
      try {
        setSubmitting(true);
        await dispatch(loginUser(values)).unwrap();
        router.push("/");
      } catch (error) {
        console.error(error);
        setErrors({
          email: "invalid email or password",
          password: "invalid email or password",
        });
      } finally {
        setSubmitting(false);
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search