next.js 页面刷新在组件内不工作

kdfy810k  于 2023-06-22  发布在  其他
关注(0)|答案(2)|浏览(209)

bounty将在6天内到期。回答此问题可获得+100声望奖励。lost_in_the_source希望引起更多关注这个问题。

我有一个受保护的 Jmeter 板页面,其中包含评论列表。当添加新评论时,我想刷新页面。但是,这并不起作用。具体来说,useRouter().refresh什么也不做。我有一个显示在 Jmeter 板页面上的AddReview组件。它是一个按钮,当点击时,触发一个允许用户输入评论数据的模态。
下面是AddReview组件的代码:

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

我使用会话对象,这样我就可以在将每个评论添加到数据库时记录其所有者/作者。在Dashboard页面上,还有一个会话对象,用于验证用户是否登录。下面是 Jmeter 板页面的代码。

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

我应该怎么做才能让useRouter().refresh函数真正刷新页面?
编辑:这里是我调用的函数,用于添加新的评论,以防提供更多的上下文:

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

yi0zb3m41#

您的 Jmeter 板页面没有刷新,因为您使用的客户端组件不涉及任何服务器端数据获取。这是基于Next.js documentation的预期行为:
router.refresh():刷新当前路由。向服务器发出新请求、重新获取数据请求并重新呈现服务器组件。客户端将合并更新后的React服务器组件有效载荷,而不会丢失未受影响的客户端React(例如useState)或浏览器状态(例如滚动位置)。
根据您当前的实现,您只在初始页面呈现时获取一次评论列表。
您可以通过几种不同的方式实现所需的行为。
1.将 Jmeter 板页面重构为服务器组件并获取数据服务器端-https://nextjs.org/docs/app/building-your-application/data-fetching/fetching
1.以状态(useState)存储评论列表,并在添加新评论时重新获取数据。
希望这能帮上忙。

u5i3ibmn

u5i3ibmn2#

我认为这是因为你有一个服务器组件,它呈现客户端组件AddReview。当你调用router.refresh时,你应该告诉服务器组件发出一个新的请求并获取最新的数据。为此,使用useTransitionHook

import {  useTransition } from 'react';

  
export default function AddReview()
{

const [isPending, startTransition] = useTransition();

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

         startTransition(()=>{
              router.refresh()
         })    
    }
}
  • 您当前的fetch请求被缓存。您可能需要使用no-store选项来始终获取最新数据

this explainsuseTransition
在React 18之前,渲染是同步的。这意味着一旦React开始渲染,在它完成渲染组件之前,没有任何东西可以阻止它。但是,对于并发渲染,React可以暂停渲染并稍后继续,或者完全中止渲染。这是一个重要的新实现,使我们能够为用户提供更流畅的用户体验。
我们可以使用useTransition钩子来告诉React,某个状态更改将导致昂贵的渲染。React将降低这种状态更改的优先级,允许其他渲染更快地进行,提供一个响应非常快的UI。这种昂贵的渲染被称为过渡更新,应该立即发生的渲染被称为紧急更新。通常,键入、点击和按下被视为紧急更新,因为它们应该为用户提供即时响应,以确保良好的用户体验。

相关问题