Next.js组件内useRouter().refresh无法刷新页面的解决问询
问题根源
你遇到的router.refresh()无效的核心原因有两个:
- 数据获取逻辑错误:Dashboard组件中
const _reviews = getAllReviews();写在组件外部,只会在组件首次加载时执行一次,后续即使调用页面刷新,也不会重新获取最新评论数据。 - 客户端组件的限制:
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
相关产品推荐
相关产品推荐

