1

I have the react client component, it's a part of a next.js app, this component is a simple form that sends it's formData to a next.js server action through an async function that will do the following steps:

  1. Set form button to be disabled & message to "Loading".
  2. Send formData to Next.JS via an async server action.
  3. Set form button to be enabled & message to error if error.

The problem seems to be that react is batching my setState calls, so in execution it's as if step 1 doesn't even happen, just step 2 + 3.

I can't figure out how to circumvent this behaviour.
Here's the source code:

"use client";

import { SendGiftAction } from "@/app/actions/SendGiftAction";
import { useState } from "react";

export default function GoldGiftForm()
{
    let [interactable, SetInteractable] = useState(true);
    let [message, setMessage] = useState("");

    async function Execute(data: FormData)
    {
        //These won't change the UI
        SetInteractable(false);
        setMessage("Loading");
        //-------------------------

        //Next.JS Server action
        let response = await SendGiftAction(data);

        //These will change the UI
        SetInteractable(true);
        setMessage(response.Success ? "" : response.Error);
        //------------------------
    }

    return (
        <form action={Execute}>
            <h3>Send Gold Gift</h3>

            <input
                name="userID"
                type="text"
                placeholder="User ID"
            />

            <input
                name="gold"
                type="number"
                placeholder="Gold"
            />

            <button type="submit" disabled={!interactable}> Send Gift </button>

            <p>{message}</p>
        </form>
    );
}

This is a code snippet for SendGiftAction: https://pastebin.com/YYQeG0m4

Which is a wrapper that validates data and invokes SendSystemGift: https://pastebin.com/uD0LLEFL

Both are standard async functions really.

4
  • I've used this pattern many times and it have worked perfectly. I would that SendGiftAction takes very few time to execute so the loading is never shown. Could it be? Commented Sep 4, 2024 at 9:43
  • What does SendGiftAction look like? Commented Sep 4, 2024 at 10:43
  • I have modified the post to include source snippets of SendGiftAction and its dependency, I have also added an artificial 10 second delay to the function, it's still behaving the same, UI not updating. Commented Sep 4, 2024 at 11:03
  • React with NextJS kind of does forms slightly different to the standard client side React, I assume so that it can handle server actions etc. So for UI updates use const { pending } = useFormStatus(); instead of of using state. Commented Sep 4, 2024 at 11:19

1 Answer 1

0

You need to understand how async call will excute in your function

//These will run immediately
    SetInteractable(false);
    setMessage("Loading");
    //-------------------------

    //This will take time to excute 
    let response = await SendGiftAction(data);

    //So in this time it will excute before api call internall
    SetInteractable(true);
    setMessage(response.Success ? "" : response.Error);

This is modified code

//These will run immediately
    SetInteractable(false);
    setMessage("Loading");

    //This will take time to excute 
    let response = await SendGiftAction(data).then((response)=>{SetInteractable(true);
    setMessage(response.Success ? "" : response.Error);});
Sign up to request clarification or add additional context in comments.

3 Comments

I'm not sure that's true in this instance? Await is blocking. The issue is that the state setters are being called within an asynchronous function, which does not work in many cases.
If use use await, then you don't use then, as you can can call the next intruction in the next line. The await tells to wait for the line to finish and the instruction returns a value instead of a promise.
This code causes the same issue unfortunately streamable.com/n825h0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.