Next.js Discord

Discord Forum

Loading State Not working In Form Component

Unanswered
Arinji posted this in #help-forum
Open in Discord
form.tsx
"use client";
import { useToast } from "@/hooks/useToast";
import { CreateTodoAction } from "@/lib/actions/todo/create";
import { Loader2 } from "lucide-react";
import {
  experimental_useFormState as useFormState,
  experimental_useFormStatus as useFormStatus,
} from "react-dom";
export function Form() {
  const initialState = {
    type: "success",
    message: "",
    id: 0,
  };

  const [state, formAction] = useFormState(CreateTodoAction, initialState);
  const { pending } = useFormStatus();

  useToast({
    message: state.message,
    type: state.type,
    successMessage: "Successfully Created Todo",
    successRoute: `/dash/todo/${state.id}`,
  });
  return (
    <form
      action={formAction}
      className=""
    >
      <div className="...">
        <label htmlFor="name" className="">
          Name
        </label>
        <input
          type="text"
          name="name"
          id="name"
          required
          maxLength={50}
          minLength={1}
          className="..."
        />
      </div>
      <div className="...">
        <label htmlFor="name" className="">
          Description
        </label>
        <textarea
          name="description"
          id="description"
          required
          maxLength={100}
          minLength={10}
          className="..."
        />
      </div>
      <div className="...">
        <button
          type="submit"
          className="..."
        >
          {pending && <Loader2 className="animate-spin" />} <p>Create Todo</p>
        </button>
      </div>
    </form>
  );
}


Action:
"use server";
export async function CreateTodoAction(prevState: any, formData: FormData) {
  const name = formData.get("name");
  const desc = formData.get("description");
  setTimeout(() => {
    console.log(name, desc);
  }, 2000);

  return {
    message: "Todo Created",
    success: true,
  };
}

The Loader does not Show Up, any idea why? The variables do get logged out correctly

13 Replies

Thing is, this works
"use client";
import { useToast } from "@/hooks/useToast";
import { CreateTodoAction } from "@/lib/actions/todo/create";
import { Loader2 } from "lucide-react";
import { experimental_useFormState as useFormState } from "react-dom";
import { SubmitButton } from "./submit";
export function Form() {
  const initialState = {
    type: "success",
    message: "",
    id: 0,
  };

  const [state, formAction] = useFormState(CreateTodoAction, initialState);

  useToast({
    message: state.message,
    type: state.type,
    successMessage: "Successfully Created Todo",
    successRoute: `/dash/todo/${state.id}`,
  });
  return (
    <form
      action={formAction}
      className="w-full xl:w-[70%] scale-90 md:scale-100 h-full flex flex-col items-center justify-center gap-4 bg-slate-300 rounded-md border-4 shadow-[4px_4px_0_#000] p-4 border-black"
    >
      <div className="w-full h-full flex flex-col items-start justify-center gap-2">
        <label htmlFor="name" className="text-2xl text-black font-bold">
          Name
        </label>
        <input
          type="text"
          name="name"
          id="name"
          required
          maxLength={50}
          minLength={1}
          className="w-full max-w-[700px] px-2 h-10 ml-5 rounded-md outline-1 bg-gray-200 outline-gray-200 font-medium "
        />
      </div>
      <div className="w-full h-full flex flex-col items-start justify-center gap-2">
        <label htmlFor="name" className="text-2xl text-black font-bold">
          Description
        </label>
        <textarea
          name="description"
          id="description"
          required
          maxLength={100}
          minLength={10}
          className="w-full max-w-[700px] px-2 py-2 h-20 ml-5 rounded-md outline-1 bg-gray-200 outline-gray-200 font-medium "
        />
      </div>
      <SubmitButton />
    </form>
  );
}

Where i call this in the form, you can see the loader, but why is this happening :/
Ive been going through the docs, i dont see what im doing wrong
Bump :fine:
first thing i see in the action
"use server";
export async function CreateTodoAction(prevState: any, formData: FormData) {
  const name = formData.get("name");
  const desc = formData.get("description");
  setTimeout(() => {
    console.log(name, desc);
  }, 2000);

  return {
    message: "Todo Created",
    success: true,
  };
}


the timeout will not work. It will return immediately.
You have to await a promise with a timeout to make it work like that:

await new Promise((resolve) => setTimeout(resolve, 2000))
just an experiment but would it work if you wrap
useToast({
    message: state.message,
    type: state.type,
    successMessage: "Successfully Created Todo",
    successRoute: `/dash/todo/${state.id}`,
  });
in a useEffect?
useEffect(() => {
  useToast({
    message: state.message,
    type: state.type,
    successMessage: "Successfully Created Todo",
    successRoute: `/dash/todo/${state.id}`,
  })
 }, [useToast, state]
)
😄 yeah
but i dont see how the useFormStatus would matter cause of that :(
could it be that its experimental so its broken?
no idea tbh. In a project of mine i did use toasts too on a form. I used useTransition with onSubmit on the form
this worked pretty well