Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Page refresh not working from within component

I have a protected dashboard page that contains a list of reviews. When a new review is added, I want to refresh the page. However, this does not work. Specifically, useRouter().refresh does nothing. I have an AddReview component that is displayed on the dashboard page. It's a button that, when clicked, triggers a modal that allows the user to enter review data.

Here is the code for the AddReview component:

"use client";
import { AiOutlinePlus } from 'react-icons/ai';
import Modal from './Modal.js';
import { useState } from 'react';
import { addReview, getAllReviews } from '/api';
import { useRouter } from "next/navigation";
import Router from 'next/navigation';
import { useSession } from 'next-auth/react';
import { v4 as uuidv4 } from 'uuid';

export default function AddReview()
{
  const { data: session } = useSession();
  const router = useRouter();
  const [modalOpen, setModalOpen] = useState(false);
  const [newContentCreatorName, setNewContentCreatorName] = useState("");
  const [newRating, setNewRating] = useState("");
  const [newText, setNewText] = useState("");

  const handleSubmitNewTodo = async (e) => {
    e.preventDefault();
                // API to add review
    await addReview({
      id: uuidv4(),
      contentCreatorName: newContentCreatorName,
      rating: newRating,
      text: newText,
      owner: session.user.email,
    });

    setNewContentCreatorName("");
    setNewRating("");
    setNewText("");
    setModalOpen(false);
    router.refresh(); // refresh page to show new item in ReviewList
  };

  return (
  <div>
    <button 
      onClick={() => setModalOpen(true)} 
      className="btn btn-primary w-full">
        Add new review <AiOutlinePlus className="ml-2" size={20}/>
    </button>
    <Modal modalOpen={modalOpen} setModalOpen={setModalOpen}>
      <form onSubmit={handleSubmitNewTodo} className="w-full max-w">
        <h3 className="font-bold text-lg mb-6 text-center">Add review</h3>
        <div>
          <input 
            value={newContentCreatorName} 
            onChange={e => setNewContentCreatorName(e.target.value)} 
            type="text" 
            placeholder="Content creator name" 
                className="block input input-bordered w-full mb-4" />
          <input 
            value={newRating} 
            onChange={e => setNewRating(e.target.value)} 
            type="number" 
            placeholder="Rating (out of 5)" 
                className="block input input-bordered w-full mb-4" />
          <input 
            value={newText} 
            onChange={e => setNewText(e.target.value)} 
            type="text" 
            placeholder="Review" 
                className="block input input-bordered w-full mb-4" />

          <button className="btn" type="submit">Submit</button>
        </div>
      </form>
    </Modal>
  </div>
  );
}

I am using the session object so that I can record the owner/author of each review as it's added to the databse. On the Dashboard page, there is also a session object that is used to validate if the user is logged in. Here is the code for the Dashboard page.

"use client";

import AddReview from '../components/AddReview';
import ReviewList from '../components/ReviewList';

import { getAllReviews } from '/api';
import { use } from 'react';

import { useSession } from "next-auth/react";

const _reviews = getAllReviews(); // API to fetch reviews

export default function Dashboard() {
  const reviews = use(_reviews);
  console.log(reviews);

  const { data: session, status } = useSession({
    required: true,
  });
  if (status === "loading")
    return <div>Session is loading...</div>;

  return (
    <>
      <div className="text-center my-5 flex flex-col gap-4">
        <h1 className="text-2xl font-bold">Yelper</h1>
        <AddReview />
      </div>
      {/* A component showing list of reviews (should be rerendered to reflect new review added) */}
      <ReviewList reviews={reviews} email={session?.user.email} />
    </>
  );
}

What should I do to have the useRouter().refresh function actually refresh the page?

EDIT: Here's the function that I call to add a new review, in case that gives more context:

export async function addReview(review) {
  const res = await fetch(`${baseUrl}/reviews`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(review).trim()
  });
  const newReview = await res.json();
  return newReview;
}
like image 981
Edward Karak Avatar asked Dec 04 '25 23:12

Edward Karak


1 Answers

I think that is because you have a server component which renders the client component AddReview. when you call router.refresh you should actually tell server component to make a new request and get the latest data. for this use useTransitionHook.

import {  useTransition } from 'react';

  
export default function AddReview()
{

const [isPending, startTransition] = useTransition();


    const handleSubmitNewTodo = async (e) => {
         ...
         ...

         startTransition(()=>{
              router.refresh()
         })    
    }
}
  • your current fetch request is cached. you might need to use no-store option to get always the fresh data

this explains useTransition

Before React 18, rendering was synchronous. This meant that once React started rendering, nothing could stop it until it completed rendering the component. However, with concurrent rendering, React can pause the rendering and continue with it later or abort the rendering altogether. This is an important new implementation that allows us to provide a more fluid user experience to our users.

We can use the useTransition hook to tell React that a certain state change will result in an expensive rendering. React will then deprioritize this state change allowing other renderings to take place faster providing a very responsive UI. Such expensive renderings are called transition updates and the ones that should take place immediately are called urgent updates. Usually, typing, clicking, and pressing are considered urgent updates as they should provide users with an immediate response to ensure a good user experience.

  • or you could try revalidatePath

     import { revalidatePath } from "next/cache";
    
     const handleSubmitNewTodo = async (e) => {
           ...
           ...
    
           // this also refreshes the page
           revalidatePath("/");
      }
    
like image 105
Yilmaz Avatar answered Dec 07 '25 23:12

Yilmaz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!