Next.js Discord

Discord Forum

Failed to execute 'json' on 'Response': body stream already read

Answered
English Lop posted this in #help-forum
Open in Discord
English LopOP
Attempted simple usage of suspense but hitting this roadblock. From what I can tell i've only read the body once

/src/app/player/page.tsx
"use client";

import { notFound, useSearchParams } from "next/navigation"
import { Suspense } from "react";
import { CircularProgress } from "@nextui-org/react";
import { PlayerHandler } from "@/components/PlayerHandler";

let body: any;


export async function PlayerHandlerWrapper({ promise }: { promise: Promise<Response> }) {
    const res = await promise
    body = body ?? await res.json()
    return <PlayerHandler questions={body.data} />
}

export default function Player() {
    const searchParams = useSearchParams()
    const id = searchParams.get('id')

    if (!id) notFound()

    const response = fetch('/api/getDoki', {
        method: 'POST',
        body: JSON.stringify({ id })
    })

    return <Suspense fallback={<CircularProgress />}>
        <PlayerHandlerWrapper promise={response} />
    </Suspense>
}


/src/components/PlayerHandler.tsx
"use client";

import { Question } from "@/helpers";
import { useState } from "react";

const enum Status {
    QuestionShown,
    Wrong,
    Correct,
}

interface PlayerState {
    status: Status
}


export function PlayerHandler({ questions }: { questions: Question[] }) {
    const [PlayerState, setPlayerState] = useState<PlayerState>({
        status: Status.QuestionShown
    })

    return <>
        {questions}
    </>
}
Answered by Ray
export default function Player({
  searchParams,
}: {
  searchParams: { id: string };
}) {
  const id = searchParams.id;

  if (!id) notFound();

  return (
    <>
      <Suspense fallback={<div>loading...</div>}>
        <PlayerHandlerWrapper id={id} />
      </Suspense>
    </>
  );
}

export async function PlayerHandlerWrapper({ id }: { id: string }) {
  const response = await fetch("http://localhost:3000/api/json", {
    method: "POST",
    body: JSON.stringify({ id }),
  });
  const body = await response.json();
  return <PlayerHandler questions={body.data} />;
}
View full answer

35 Replies

is '/api/getDoki' a api route or external api?
@Ray is `'/api/getDoki'` a api route or external api?
English LopOP
an api route
can you show the code of api route
English LopOP
import { NextRequest } from "next/server";
import { readFile } from "fs/promises";
import { join } from "path";

export async function POST(request: NextRequest) {
    const res = await request.json()
    if ("id" in res && typeof res.id === 'string') {
        try {
            const data = await readFile(join(process.cwd(), 'dokimions', res.id), 'utf8')
            return Response.json({ data })
        } catch {
            return Response.json({ data: null })
        }
    }
}
Player is client component and PlayerHandlerWrapper is server component?
@Ray Player is client component and PlayerHandlerWrapper is server component?
English LopOP
playerhandlerwrapper is an async component and they're all client
async component = server component
@Ray async component = server component
English LopOP
but it's used in the suspense
it is still a server component
English LopOP
isn't it just a promise of a reactnode
and you can't import a server component in a client component
@Ray it is still a server component
English LopOP
I put "use client"; at the top though
@English Lop I put "use client"; at the top though
English LopOP
i edited the original message to show all the code
if you put 'use client' on top then it can't await the promise
English LopOP
wait, if you're not supposed to use async then how would u go about using suspense with fetch
because that's the example i saw
what example you saw?
@English Lop because that's the example i saw
English LopOP
I guess it was incorrect
Could you please point me in the right direction as to how to properly go about doing this?
export default function Player({
  searchParams,
}: {
  searchParams: { id: string };
}) {
  const id = searchParams.id;

  if (!id) notFound();

  return (
    <>
      <Suspense fallback={<div>loading...</div>}>
        <PlayerHandlerWrapper id={id} />
      </Suspense>
    </>
  );
}

export async function PlayerHandlerWrapper({ id }: { id: string }) {
  const response = await fetch("http://localhost:3000/api/json", {
    method: "POST",
    body: JSON.stringify({ id }),
  });
  const body = await response.json();
  return <PlayerHandler questions={body.data} />;
}
Answer
like this
I have turned Player to server component also
@Ray I have turned Player to server component also
English LopOP
i tried to use search params before with server components but it gave me an error
what error?
English LopOP
that I cannot use the useSearchParams hook in server components
useSearchParams need to be use with client component
however, page server component receive the searchParams as props
so you don't need to turn it to client component
does it work for you?
@Ray does it work for you?
English LopOP
I went to bed
Ill do it now
@Ray does it work for you?
English LopOP
has been successful
thank you