How can I add the Suspense tags to the following code :-
"use client";
import { Suspense, useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Suspense } from 'react'
import Form from "@ponents/Form";
const UpdatePrompt = () => {
const router = useRouter();
const searchParams = useSearchParams();
const promptId = searchParams.get("id");
const [post, setPost] = useState({ prompt: "", tag: "", });
const [submitting, setIsSubmitting] = useState(false);
useEffect(() => {
const getPromptDetails = async () => {
const response = await fetch(`/api/prompt/${promptId}`);
const data = await response.json();
setPost({
prompt: data.prompt,
tag: data.tag,
});
};
if (promptId) getPromptDetails();
}, [promptId]);
const updatePrompt = async (e) => {
e.preventDefault();
setIsSubmitting(true);
if (!promptId) return alert("Missing PromptId!");
try {
const response = await fetch(`/api/prompt/${promptId}`, {
method: "PATCH",
body: JSON.stringify({
prompt: post.prompt,
tag: post.tag,
}),
});
if (response.ok) {
router.push("/");
}
} catch (error) {
console.log(error);
} finally {
setIsSubmitting(false);
}
};
return (
<Suspense>
<Form
type='Edit'
post={post}
setPost={setPost}
submitting={submitting}
handleSubmit={updatePrompt}
/>
</Suspense>
);
};
export default UpdatePrompt;
I tried adding it in the return statement but during deployment in Vercel this error showed :-
Error:
x Unexpected token. Did you mean {'}'}
or }
?
,-[/vercel/path0/app/update-prompt/page.jsx:63:1]
Can someone help me in adding the Suspense tags in the above code. Thanks in Advance!
How can I add the Suspense tags to the following code :-
"use client";
import { Suspense, useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Suspense } from 'react'
import Form from "@ponents/Form";
const UpdatePrompt = () => {
const router = useRouter();
const searchParams = useSearchParams();
const promptId = searchParams.get("id");
const [post, setPost] = useState({ prompt: "", tag: "", });
const [submitting, setIsSubmitting] = useState(false);
useEffect(() => {
const getPromptDetails = async () => {
const response = await fetch(`/api/prompt/${promptId}`);
const data = await response.json();
setPost({
prompt: data.prompt,
tag: data.tag,
});
};
if (promptId) getPromptDetails();
}, [promptId]);
const updatePrompt = async (e) => {
e.preventDefault();
setIsSubmitting(true);
if (!promptId) return alert("Missing PromptId!");
try {
const response = await fetch(`/api/prompt/${promptId}`, {
method: "PATCH",
body: JSON.stringify({
prompt: post.prompt,
tag: post.tag,
}),
});
if (response.ok) {
router.push("/");
}
} catch (error) {
console.log(error);
} finally {
setIsSubmitting(false);
}
};
return (
<Suspense>
<Form
type='Edit'
post={post}
setPost={setPost}
submitting={submitting}
handleSubmit={updatePrompt}
/>
</Suspense>
);
};
export default UpdatePrompt;
I tried adding it in the return statement but during deployment in Vercel this error showed :-
Error:
x Unexpected token. Did you mean {'}'}
or }
?
,-[/vercel/path0/app/update-prompt/page.jsx:63:1]
Can someone help me in adding the Suspense tags in the above code. Thanks in Advance!
Share Improve this question asked Mar 15, 2024 at 19:29 Anantesh GopalAnantesh Gopal 911 gold badge1 silver badge6 bronze badges6 Answers
Reset to default 5When using <UpdatePrompt />
, wrap it in a <Suspense />
to avoid marking the entire route as dynamic route.
import {Suspense} from "react";
// ...
<Suspense>
<UpdatePrompt />
</Suspense>
<Suspense>
must be outside of the ponent that uses runtime values (e.g. searchParams). so putting it inside the UpdatePrompt
ponent won't work.
Update
Based on the repo shared in the ments, https://github./AnanteshG/Quasar/blob/main/app/update-prompt/page.jsx
The default export of page.jsx is used internally by Next.js to be rendered in the route. Update your code to wrap the UpdatePrompt in a parent ponent:
const Page = () => {
return (
<Suspense>
<UpdatePrompt/>
</Suspense>
)
}
export default Page
remember to remove export default UpdatePrompt
line
wrap the full ponent in a <Suspense />
like this:
const UpdatePrompt = () => {
........
return (
<Form ..... />
);
};
const Page = () => {
return (
<Suspense>
<UpdatePrompt />
</Suspense>
)
}
export default Page
The main reason for this error is in SessionProvider. The solution in official doc or given by other will not work. Just move {children} inside suspense boundary and that's all.
"use client";
import { SessionProvider } from "next-auth/react";
import { ReactNode, Suspense } from "react";
export default function AuthSessionProvider({ children }: { children: ReactNode }) {
return <SessionProvider>
<Suspense fallback={null}>
{children}
</Suspense>
</SessionProvider>;
}
This will solve your problem
Adding a loading.tsx
next to the root layout.tsx
solved it for me
Suspense for data fetching is supported only in React 18 or higher. Make sure you're using the correct version in your project (Next.js 13.x should be fine with React 18).
If you're using Suspense for fetching data directly, you’d typically use a Suspense boundary around the ponent and use something like React Query or useSWR to fetch data asynchronously, which would work out of the box with Suspense.
"use client";
import { Suspense, useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import dynamic from 'next/dynamic';
const Form = dynamic(() => import("@ponents/Form"), { suspense: true });
const UpdatePrompt = () => {
const router = useRouter();
const searchParams = useSearchParams();
const promptId = searchParams.get("id");
const [post, setPost] = useState({ prompt: "", tag: "" });
const [submitting, setIsSubmitting] = useState(false);
useEffect(() => {
const getPromptDetails = async () => {
const response = await fetch(`/api/prompt/${promptId}`);
const data = await response.json();
setPost({
prompt: data.prompt,
tag: data.tag,
});
};
if (promptId) getPromptDetails();
}, [promptId]);
const updatePrompt = async (e) => {
e.preventDefault();
setIsSubmitting(true);
if (!promptId) return alert("Missing PromptId!");
try {
const response = await fetch(`/api/prompt/${promptId}`, {
method: "PATCH",
body: JSON.stringify({
prompt: post.prompt,
tag: post.tag,
}),
});
if (response.ok) {
router.push("/");
}
} catch (error) {
console.log(error);
} finally {
setIsSubmitting(false);
}
};
return (
<Suspense fallback={<div>Loading...</div>}>
<Form
type="Edit"
post={post}
setPost={setPost}
submitting={submitting}
handleSubmit={updatePrompt}
/>
</Suspense>
);
};
export default UpdatePrompt;
If you're using the App Router and Server Components and only need to access URL parameters and don't mind dynamic rendering, it's best to avoid useSearchParams
and Suspense
entirely. Using them can introduce unnecessary delays because everything inside Suspense is rendered on the client side, causing a visible lag in loading.
Instead, use the searchParams property of the Page ponent!
Since searchParams
are part of the URL, the server reads them directly from the request and provides them to the Page ponent. This means you can access them in Server Components or pass them down to Client Components, resulting in instant renders.
You can check out the official documentation for an example or take a look at my slightly modified version, which I use in my projects:
// This is Page as Server Component
type SearchParams = {
searchParams?: Promise<Record<string, string>>;
};
export default async function Page({ searchParams }: SearchParams) {
const urlSearchParams = new URLSearchParams(await searchParams);
return (
<p>
{urlSearchParams.has("query")
? `This is your query: ${urlSearchParams.get("query")}`
: "No query param provided"}
</p>
);
}
Or you can check out the official dashboard-app example.