You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js组件内useRouter().refresh无法刷新页面的解决问询

问题根源

你遇到的router.refresh()无效的核心原因有两个:

  1. 数据获取逻辑错误:Dashboard组件中const _reviews = getAllReviews();写在组件外部,只会在组件首次加载时执行一次,后续即使调用页面刷新,也不会重新获取最新评论数据。
  2. 客户端组件的限制:router.refresh()主要用于触发服务器组件的重新渲染,而你的Dashboard是客户端组件,且用use()钩子处理Promise的方式无法触发数据重新拉取。

两种解决方案

方案一:将Dashboard改为服务器组件(推荐)

把Dashboard改成服务器组件后,router.refresh()会触发服务器重新渲染页面,自动拉取最新评论数据,同时能更好地处理权限验证。

修改Dashboard.js:

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

import { getAllReviews } from '/api';
import { getServerSession } from "next-auth/next";
import { authOptions } from "../api/auth/[...nextauth]"; // 替换为你的nextauth配置路径
import { redirect } from 'next/navigation';

export default async function Dashboard() {
  // 服务器端验证session
  const session = await getServerSession(authOptions);
  if (!session) {
    redirect('/api/auth/signin');
  }

  // 服务器端获取最新评论
  const reviews = await getAllReviews();

  return (
    <>
      <div className="text-center my-5 flex flex-col gap-4">
        <h1 className="text-2xl font-bold">Yelper</h1>
        <AddReview />
      </div>
      <ReviewList reviews={reviews} email={session.user.email} />
    </>
  );
}

此时AddReview组件中的router.refresh()会正常生效,因为服务器组件会重新渲染并拉取最新数据。

方案二:保持客户端组件,手动触发数据更新

如果必须保留客户端组件,可以通过父组件传递回调函数,在添加评论后手动重新获取评论列表,无需依赖router.refresh()。

1. 修改Dashboard.js

"use client";

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

import { getAllReviews } from '/api';
import { useState, useEffect } from 'react';
import { useSession } from "next-auth/react";

export default function Dashboard() {
  const [reviews, setReviews] = useState([]);
  const [loading, setLoading] = useState(true);

  const { data: session, status } = useSession({
    required: true,
  });

  // 初始化获取评论
  useEffect(() => {
    const fetchReviews = async () => {
      const data = await getAllReviews();
      setReviews(data);
      setLoading(false);
    };
    fetchReviews();
  }, []);

  // 添加评论后重新拉取数据的回调
  const refreshReviews = async () => {
    const newReviews = await getAllReviews();
    setReviews(newReviews);
  };

  if (status === "loading" || loading)
    return <div>Loading...</div>;

  return (
    <>
      <div className="text-center my-5 flex flex-col gap-4">
        <h1 className="text-2xl font-bold">Yelper</h1>
        <AddReview onReviewAdded={refreshReviews} />
      </div>
      <ReviewList reviews={reviews} email={session?.user.email} />
    </>
  );
}

2. 修改AddReview.js

去掉router.refresh(),调用父组件传递的回调函数:

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

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

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

    setNewContentCreatorName("");
    setNewRating("");
    setNewText("");
    setModalOpen(false);
    // 调用回调刷新评论列表
    await onReviewAdded();
  };

  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>
  );
}

内容的提问来源于stack exchange,提问作者lost_in_the_source

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 14:37:02