英文:
NextJS 13 Updating Server Component Data
问题
我正在学习/适应 NextJS 13,它带来了新的APP文件夹。我在弄清楚如何在不重新加载页面/应用的情况下更新服务器组件上的数据时遇到了困难。目前,我的HomePage服务器组件从MongoDB获取项目(事件)列表。
如果在幕后更改了DB数据,然后在我的应用程序中导航到另一个路由,然后返回到HomePage而不重新加载,新数据不会显示。只有在直接从浏览器中进行强制刷新页面时才会显示新数据。对于我的EventDetails组件也是如此。如果我在加载应用程序后直接在数据库中更改某个事件的数据,那么在导航到该事件的详细信息时,除非我直接重新加载页面,否则不会显示该更改。
我在fetch函数中设置了以下选项
catch: 'no-cache'
next: { revalidate: 1 }
我还尝试在组件文件中设置以下导出
export const revalidate = 0;
export const dynamic = 'force-dynamic';
但仍然无法更新值。
这是我的完整代码。
// HomePage组件(app/page.jsx)
import React from 'react';
import MeetupList from './_components/meetups/meetupList';
export const revalidate = 0;
export const dynamic = 'force-dynamic';
const fetchMeetups = async () => {
const response = await fetch('http://localhost:3000/api/meetup', {
catch: 'no-cache',
next: { revalidate: 1 },
});
const data = await response.json();
return data;
};
const HomePage = async () => {
const meetups = await fetchMeetups();
return (
<>
</>
);
};
export default HomePage;
//MeetupList.jsx
import MeetupItem from './MeetupItem';
import styles from './MeetupList.module.css';
export const dynamic = 'force-dynamic';
function MeetupList({ meetups }) {
return (
-
{meetups.map((meetup) => (
))}
);
}
export default MeetupList;
这是否与我认为仍处于Beta模式的新Server Action有关?
谢谢
CES
英文:
So I’m in the process of learning/adapting to NextJS 13 with its new APP folder. I’m having a hard time figuring out how to update data on server components without having to reload the page/app.. Currently my HomePage server component fetches a list of items (events) from MongoDB. If from behind the scene I change the DB data and then navigate to another route on my app and back to the HomePage without reloading, the new data is not displayed. It’s only displayed if I hard reload the page directly from the browser. The same goes for my EventDetails component. If I change one of the event’s data directly on the database after loading the app in the browser, that change is not displayed in the app when I navigate to that event's detail unless I directly reload the page.
I have set the following option in the fetch function
catch: 'no-cache'
next: { revalidate: 1 },
And also tried settings this exports in the component file
export const revalidate = 0;
export const dynamic = 'force-dynamic'
;
But still its not updating the values.
Here is my full code.
// HomePage Component (app/page.jsx)
import React from 'react';
import MeetupList from './_components/meetups/meetupList';
export const revalidate = 0;
export const dynamic = 'force-dynamic';
const fetchMeetups = async () => {
const response = await fetch('http://localhost:3000/api/meetup', {
catch: 'no-cache',
next: { revalidate: 1 },
});
const data = await response.json();
return data;
};
const HomePage = async () => {
const meetups = await fetchMeetups();
return (
<>
<MeetupList meetups={meetups} />
</>
);
};
export default HomePage;
//MeetupList.jsx
import MeetupItem from './MeetupItem';
import styles from './MeetupList.module.css';
export const dynamic = 'force-dynamic';
function MeetupList({ meetups }) {
return (
<ul className={styles.list}>
{meetups.map((meetup) => (
<MeetupItem
key={meetup._id}
id={meetup._id}
image={meetup.image}
title={meetup.title}
address={meetup.address}
/>
))}
</ul>
);
}
export default MeetupList;
Is this something I have to do with the new Server Action which I believe is still in Beta Mode?
Thanks
CES
答案1
得分: 3
这似乎是Next 13中长期存在的问题。请查看以下日期至2022年11月的问题票证,并随时点赞。
https://github.com/vercel/next.js/issues/42991
您可以在上述讨论中找到多种解决方法(其中一些可能不再适用)。请查看哪种方法最适合您的情况,但这是我目前正在使用的一种解决方法:
// components/Link.tsx
"use client";
import { ComponentProps, forwardRef } from "react";
import NextLink from "next/link";
import { useRouter } from "next/navigation";
export default forwardRef<
HTMLAnchorElement,
Omit<ComponentProps<typeof NextLink>, "href"> & {
href: string;
refresh?: boolean;
}
>(function Link({ href, onClick, refresh, children, ...rest }, ref) {
const router = useRouter();
return refresh ? (
<a
ref={ref}
href={href}
onClick={(event) => {
onClick?.(event);
if (!event.defaultPrevented) {
event.preventDefault();
router.push(href);
router.refresh();
}
}}
{...rest}
>
{children}
</a>
) : (
<NextLink ref={ref} href={href} onClick={onClick} {...rest}>
{children}
</NextLink>
);
});
// test/page.tsx
import Link from "@/components/Link";
<Link refresh href="/">Home</Link>
请注意,上述代码中的HTML标签和JSX代码已经保留在英文状态下,不需要翻译。
英文:
Apparently, this is a long-standing issue in Next 13. Please see the following ticket dating back to Nov 2022 and feel free to upvote.
https://github.com/vercel/next.js/issues/42991
You can find numerous workarounds in the above thread (some of them no longer work though). Please see which one works best in your case, but here is a workaround I'm using for now:
// components/Link.tsx
"use client";
import { ComponentProps, forwardRef } from "react";
import NextLink from "next/link";
import { useRouter } from "next/navigation";
export default forwardRef<
HTMLAnchorElement,
Omit<ComponentProps<typeof NextLink>, "href"> & {
href: string;
refresh?: boolean;
}
>(function Link({ href, onClick, refresh, children, ...rest }, ref) {
const router = useRouter();
return refresh ? (
<a
ref={ref}
href={href}
onClick={(event) => {
onClick?.(event);
if (!event.defaultPrevented) {
event.preventDefault();
router.push(href);
router.refresh();
}
}}
{...rest}
>
{children}
</a>
) : (
<NextLink ref={ref} href={href} onClick={onClick} {...rest}>
{children}
</NextLink>
);
});
// test/page.tsx
import Link from "@/components/Link";
<Link refresh href="/">Home</Link>
答案2
得分: 0
官方文档 表示
> 默认情况下,所有 fetch() 请求都会自动缓存和去重。这意味着如果您发送相同的请求两次,第二个请求将重复使用第一个请求的结果。
>
> 如果满足以下条件,则请求不会被缓存:
>
> - 使用动态方法 (next/headers、export const POST 等) 且 fetch 是 POST 请求 (或者使用了 Authorization 或 cookie 头部)
> - fetchCache 配置为默认跳过缓存
> - revalidate: 0 或 cache: 'no-store' 配置在单个 fetch 上
所以为什么不尝试这样做
const HomePage = async () => {
const res = await fetch('http://localhost:3000/api/meetup', { next: { revalidate: 0 } });
const meetups = await res.json();
return (
<>
<MeetupList meetups={meetups} />
</>
);
}
英文:
> By default, all fetch() requests are cached and deduplicated automatically. This means that if you make the same request twice, the second request will reuse the result from the first request.
>
> Requests are not cached if:
>
> - Dynamic methods (next/headers, export const POST, or similar) are used
> and the fetch is a POST request (or uses Authorization or cookie
> headers)
> - fetchCache is configured to skip cache by default
> - revalidate:
> 0 or cache: 'no-store' is configured on individual fetch
So why don't you try something like that
const HomePage = async () => {
const res = await fetch('http://localhost:3000/api/meetup', { next: { revalidate: 0 } })
const meetups = res.json()
return (
<>
<MeetupList meetups={meetups} />
</>
)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论