Next.js Discord

Discord Forum

how can I display a loading state / show UI when awaiting data in an async component?

Answered
Florida White posted this in #help-forum
Open in Discord
Florida WhiteOP
I have a route /chat/[id], this route awaits data in when loaded in and also handles some logic if the chat is new or not. The logic inside the If searchParams block is causing too much delay before anything displays

Here is my file (cut some unnecessary code for post length):
type props = {
    params:{
        id: string
    },
    searchParams: { [key: string]: string | undefined } 
}


export default async function Page(props: props) {

    const messages = await drizzle query

    if(props.searchParams["new"] && props.searchParams["message"]){
        const messageId = props.searchParams["message"];
        const req = await fetch("http://localhost:3000/api/message", {
            method: "POST",
        });

        const res = await req.json();

        if(res.success){
            revalidatePath(`/chat/${props.params.id}`);
            revalidatePath("/")
            redirect(`/chat/${props.params.id}`);
        }
    }

    
    async function sendMessage(formData: FormData) {
        "use server"
        const message = formData.get("message");
            if (message) {
                const req = await fetch("http://localhost:3000/api/message", {
                    method: "POST",
                    }
                const data = await req.json();
                if(data.success){
                    revalidatePath(`/chat/${props.params.id}`);
                }
            }
    }

    return(
       <Messages messages={messages}/>
        <form action={sendMessage}/>
    )

}
Answered by Ray
use loading.tsx or <Suspense />
import { Suspense } from "react";

type props = {
    params:{
        id: string
    },
    searchParams: { [key: string]: string | undefined } 
}


export default async function Page(props: props) {

    async function sendMessage(formData: FormData) {
        "use server"
        const message = formData.get("message");
            if (message) {
                const req = await fetch("http://localhost:3000/api/message", {
                    method: "POST",
                    }
                const data = await req.json();
                if(data.success){
                    revalidatePath(`/chat/${props.params.id}`);
                }
            }
    }

    return(
        <>
        <Suspense key={JSON.stringify(searchParams)} fallback={<div>loading...</div>}>
            <MessagesContainer searchParams={searchParams} />
        </Suspense>
        <form action={sendMessage}/>
        </>
    )

}

async function MessagesContainer(props) {
    const messages = await drizzle query

    if(props.searchParams["new"] && props.searchParams["message"]){
        const messageId = props.searchParams["message"];
        const req = await fetch("http://localhost:3000/api/message", {
            method: "POST",
        });

        const res = await req.json();

        if(res.success){
            revalidatePath(`/chat/${props.params.id}`);
            revalidatePath("/")
            redirect(`/chat/${props.params.id}`);
        }
    }

    return  <Messages messages={messages}/>
}
View full answer

9 Replies

@Florida White I have a route /chat/[id], this route awaits data in when loaded in and also handles some logic if the chat is new or not. The logic inside the If searchParams block is causing too much delay before anything displays Here is my file (cut some unnecessary code for post length): tsx type props = { params:{ id: string }, searchParams: { [key: string]: string | undefined } } export default async function Page(props: props) { const messages = await drizzle query if(props.searchParams["new"] && props.searchParams["message"]){ const messageId = props.searchParams["message"]; const req = await fetch("http://localhost:3000/api/message", { method: "POST", }); const res = await req.json(); if(res.success){ revalidatePath(`/chat/${props.params.id}`); revalidatePath("/") redirect(`/chat/${props.params.id}`); } } async function sendMessage(formData: FormData) { "use server" const message = formData.get("message"); if (message) { const req = await fetch("http://localhost:3000/api/message", { method: "POST", } const data = await req.json(); if(data.success){ revalidatePath(`/chat/${props.params.id}`); } } } return( <Messages messages={messages}/> <form action={sendMessage}/> ) }
use loading.tsx or <Suspense />
import { Suspense } from "react";

type props = {
    params:{
        id: string
    },
    searchParams: { [key: string]: string | undefined } 
}


export default async function Page(props: props) {

    async function sendMessage(formData: FormData) {
        "use server"
        const message = formData.get("message");
            if (message) {
                const req = await fetch("http://localhost:3000/api/message", {
                    method: "POST",
                    }
                const data = await req.json();
                if(data.success){
                    revalidatePath(`/chat/${props.params.id}`);
                }
            }
    }

    return(
        <>
        <Suspense key={JSON.stringify(searchParams)} fallback={<div>loading...</div>}>
            <MessagesContainer searchParams={searchParams} />
        </Suspense>
        <form action={sendMessage}/>
        </>
    )

}

async function MessagesContainer(props) {
    const messages = await drizzle query

    if(props.searchParams["new"] && props.searchParams["message"]){
        const messageId = props.searchParams["message"];
        const req = await fetch("http://localhost:3000/api/message", {
            method: "POST",
        });

        const res = await req.json();

        if(res.success){
            revalidatePath(`/chat/${props.params.id}`);
            revalidatePath("/")
            redirect(`/chat/${props.params.id}`);
        }
    }

    return  <Messages messages={messages}/>
}
Answer
i forgot that
Florida WhiteOP
tyty ill try
@Ray i forgot that
Florida WhiteOP
perfect that worked, is it ok if you give me a little rundown of what happened im a bit unfamiliar with how next handles awaiting data
@Florida White perfect that worked, is it ok if you give me a little rundown of what happened im a bit unfamiliar with how next handles awaiting data
if you wrap a server component with suspense, next will not wait for rendering that component instead, it will send it to client with streaming
Florida WhiteOP
thanks! ill take a look