admin管理员组

文章数量:1288075

I'm working on a Next.js application where I'm creating a new payment record in the database. After the record is created, I want to refresh the page to display the updated list of payments. I'm using router.refresh(), but the new data isn't showing up unless I manually refresh the entire browser.

I have a page app/(user)/user/[userId]/page.tsx which is set to be dynamically rendered.

import { Suspense } from "react";
import { UserIdPageWrapper } from "./_components/userId-page-wrapper";

interface UserIdPageProps {
  params: Promise<{ userId: string }>;
}
export const dynamic = "force-dynamic";

export default async function UserIdPage({ params }: UserIdPageProps) {
  const { userId } = await params;

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserIdPageWrapper userId={userId} />
    </Suspense>
  );
}

The page uses a component called UserIdPageWrapper to fetch the user and payment data:

import { db } from "@/lib/db";
import { UserInfo } from "./userInfo";
import { redirect } from "next/navigation";

interface UserIdPageWrapperProps {
  userId: string;
}
export const UserIdPageWrapper = async ({ userId }: UserIdPageWrapperProps) => {
  const [userData, paymentsData] = await Promise.all([
    db.user.findUnique({
      where: {
        id: userId,
      },
    }),

    db.payment.findMany({
      where: {
        userId: userId,
      },
      include: {
        items: true,
      },
    }),
  ]);

  if (!userData || !paymentsData) {
    redirect("/");
  }

  return (
    <UserInfo
      user={userData}
      payments={paymentsData}
    />
  );
};

Inside the UserInfo component (a client component), I have a function handleAddPayment that sends a POST request to create a new payment:

"use client";

import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";

interface userInfoProps {
  user: User;
  payments: (Payment & { items: PaymentItem[] })[];
}

export const UserInfo = ({ user, payments }: userInfoProps) => {
  const router = useRouter();
  const [isLoading, setIsLoading] = useState(false);

  const handleAddPayment = async () => {
    setIsLoading(true);
    try {
      const res = await fetch("/api/payments", {
        method: "POST",
        body: JSON.stringify({
          userId: user.id,
          totalAmount: 0,
          supervisionRatio: 0,
        }),
        headers: {
          "Content-Type": "application/json",
        },
      });

      if (!res.ok) {
        throw new Error("Failed to add payment");
      }
      const jsonData = await res.json();

      console.log(jsonData);

      toast.success("New payment added");
      router.refresh();
    } catch (error) {
      toast.error("Failed to add payment");
    } finally {
      setIsLoading(false);
    }
  };

  // ... rest of the component
};

The /api/payments route handler looks like this:

import { NextResponse } from "next/server";
import { db } from "@/lib/db";

export async function POST(req: Request) {
  try {
    const { userId, totalAmount, supervisionRatio } = await req.json();
    const res = await db.payment.create({
      data: {
        userId,
        totalAmount,
        supervisionRatio,
        supervisionFee: (totalAmount * supervisionRatio) / 100,
        paymentDate: new Date(),
        remainingAmount: totalAmount - (totalAmount * supervisionRatio) / 100,
      },
    });

    return NextResponse.json(res);
  } catch (error) {
    console.error("[ORDERS_POST]", error);
    return new NextResponse("Internal error", { status: 500 });
  }
}

I've tried setting export const dynamic = "force-dynamic"; in my page.tsx file, but it's still not working.

What I've tried:

  • Using router.refresh() after the POST request.
  • Setting dynamic = "force-dynamic" in the page.tsx file.

What I expect:

After creating a new payment, I expect the PaymentList component to re-render with the updated list of payments without a full browser refresh.

Question:

What am I missing? Is there a caching issue, or is router.refresh() not the correct approach for this scenario? How can I ensure that the page updates with the new data after the POST request?

I'm working on a Next.js application where I'm creating a new payment record in the database. After the record is created, I want to refresh the page to display the updated list of payments. I'm using router.refresh(), but the new data isn't showing up unless I manually refresh the entire browser.

I have a page app/(user)/user/[userId]/page.tsx which is set to be dynamically rendered.

import { Suspense } from "react";
import { UserIdPageWrapper } from "./_components/userId-page-wrapper";

interface UserIdPageProps {
  params: Promise<{ userId: string }>;
}
export const dynamic = "force-dynamic";

export default async function UserIdPage({ params }: UserIdPageProps) {
  const { userId } = await params;

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserIdPageWrapper userId={userId} />
    </Suspense>
  );
}

The page uses a component called UserIdPageWrapper to fetch the user and payment data:

import { db } from "@/lib/db";
import { UserInfo } from "./userInfo";
import { redirect } from "next/navigation";

interface UserIdPageWrapperProps {
  userId: string;
}
export const UserIdPageWrapper = async ({ userId }: UserIdPageWrapperProps) => {
  const [userData, paymentsData] = await Promise.all([
    db.user.findUnique({
      where: {
        id: userId,
      },
    }),

    db.payment.findMany({
      where: {
        userId: userId,
      },
      include: {
        items: true,
      },
    }),
  ]);

  if (!userData || !paymentsData) {
    redirect("/");
  }

  return (
    <UserInfo
      user={userData}
      payments={paymentsData}
    />
  );
};

Inside the UserInfo component (a client component), I have a function handleAddPayment that sends a POST request to create a new payment:

"use client";

import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";

interface userInfoProps {
  user: User;
  payments: (Payment & { items: PaymentItem[] })[];
}

export const UserInfo = ({ user, payments }: userInfoProps) => {
  const router = useRouter();
  const [isLoading, setIsLoading] = useState(false);

  const handleAddPayment = async () => {
    setIsLoading(true);
    try {
      const res = await fetch("/api/payments", {
        method: "POST",
        body: JSON.stringify({
          userId: user.id,
          totalAmount: 0,
          supervisionRatio: 0,
        }),
        headers: {
          "Content-Type": "application/json",
        },
      });

      if (!res.ok) {
        throw new Error("Failed to add payment");
      }
      const jsonData = await res.json();

      console.log(jsonData);

      toast.success("New payment added");
      router.refresh();
    } catch (error) {
      toast.error("Failed to add payment");
    } finally {
      setIsLoading(false);
    }
  };

  // ... rest of the component
};

The /api/payments route handler looks like this:

import { NextResponse } from "next/server";
import { db } from "@/lib/db";

export async function POST(req: Request) {
  try {
    const { userId, totalAmount, supervisionRatio } = await req.json();
    const res = await db.payment.create({
      data: {
        userId,
        totalAmount,
        supervisionRatio,
        supervisionFee: (totalAmount * supervisionRatio) / 100,
        paymentDate: new Date(),
        remainingAmount: totalAmount - (totalAmount * supervisionRatio) / 100,
      },
    });

    return NextResponse.json(res);
  } catch (error) {
    console.error("[ORDERS_POST]", error);
    return new NextResponse("Internal error", { status: 500 });
  }
}

I've tried setting export const dynamic = "force-dynamic"; in my page.tsx file, but it's still not working.

What I've tried:

  • Using router.refresh() after the POST request.
  • Setting dynamic = "force-dynamic" in the page.tsx file.

What I expect:

After creating a new payment, I expect the PaymentList component to re-render with the updated list of payments without a full browser refresh.

Question:

What am I missing? Is there a caching issue, or is router.refresh() not the correct approach for this scenario? How can I ensure that the page updates with the new data after the POST request?

Share Improve this question asked Feb 22 at 15:47 MoazMoaz 193 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Since you're using NextJS with app router, you should be using revalidatePath instead of a call to router.refresh. Typically, when you perform an update in a server action or route handler, you'll need to call the revalidatePath from next-cache in order to refresh the data in the cache and to have access to the updated data.

import { revalidatePath } from "next/cache";

export async function POST(req: Request) {
  try {
    const { userId, totalAmount, supervisionRatio } = await req.json();
    const res = await db.payment.create({
      data: {
        userId,
        totalAmount,
        supervisionRatio,
        supervisionFee: (totalAmount * supervisionRatio) / 100,
        paymentDate: new Date(),
        remainingAmount: totalAmount - (totalAmount * supervisionRatio) / 100,
      },
    });

    revalidatePath("/posts") //This assumes /post is the path being revalidated.

    return NextResponse.json(res);
  } catch (error) {
    console.error("[ORDERS_POST]", error);
    return new NextResponse("Internal error", { status: 500 });
  }
}

本文标签: javascriptNextjs routerrefresh() not updating data after POST requestStack Overflow