NextJS 13 更新服务器组件数据

huangapple go评论75阅读模式
英文:

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: &#39;no-cache&#39;
next: { revalidate: 1 },



And also tried settings this exports in the component file


export const revalidate = 0;
export const dynamic = &#39;force-dynamic&#39;

;




But still its not updating the values.

Here is my full code.

// HomePage Component (app/page.jsx)
import React from &#39;react&#39;;
import MeetupList from &#39;./_components/meetups/meetupList&#39;;
export const revalidate = 0;
export const dynamic = &#39;force-dynamic&#39;;

const fetchMeetups = async () =&gt; {
  const response = await fetch(&#39;http://localhost:3000/api/meetup&#39;, {
    catch: &#39;no-cache&#39;,
    next: { revalidate: 1 },
  });

  const data = await response.json();

  return data;
};

const HomePage = async () =&gt; {
  const meetups = await fetchMeetups();
  return (
    &lt;&gt;
      &lt;MeetupList meetups={meetups} /&gt;
    &lt;/&gt;
  );
};

export default HomePage;


//MeetupList.jsx
import MeetupItem from &#39;./MeetupItem&#39;;

import styles from &#39;./MeetupList.module.css&#39;;
export const dynamic = &#39;force-dynamic&#39;;

function MeetupList({ meetups }) {
  return (
    &lt;ul className={styles.list}&gt;
      {meetups.map((meetup) =&gt; (
        &lt;MeetupItem
          key={meetup._id}
          id={meetup._id}
          image={meetup.image}
          title={meetup.title}
          address={meetup.address}
        /&gt;
      ))}
    &lt;/ul&gt;
  );
}

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

&quot;use client&quot;;

import { ComponentProps, forwardRef } from &quot;react&quot;;
import NextLink from &quot;next/link&quot;;
import { useRouter } from &quot;next/navigation&quot;;

export default forwardRef&lt;
  HTMLAnchorElement,
  Omit&lt;ComponentProps&lt;typeof NextLink&gt;, &quot;href&quot;&gt; &amp; {
    href: string;
    refresh?: boolean;
  }
&gt;(function Link({ href, onClick, refresh, children, ...rest }, ref) {
  const router = useRouter();

  return refresh ? (
    &lt;a
      ref={ref}
      href={href}
      onClick={(event) =&gt; {
        onClick?.(event);
        if (!event.defaultPrevented) {
          event.preventDefault();
          router.push(href);
          router.refresh();
        }
      }}
      {...rest}
    &gt;
      {children}
    &lt;/a&gt;
  ) : (
    &lt;NextLink ref={ref} href={href} onClick={onClick} {...rest}&gt;
      {children}
    &lt;/NextLink&gt;
  );
});
// test/page.tsx

import Link from &quot;@/components/Link&quot;;

&lt;Link refresh href=&quot;/&quot;&gt;Home&lt;/Link&gt;

答案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} />
    </>
  );
}
英文:

Official Documentation says

> 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 () =&gt; {
  const res = await fetch(&#39;http://localhost:3000/api/meetup&#39;, { next: { revalidate: 0 } })
  const meetups = res.json()

  return (
    &lt;&gt;
      &lt;MeetupList meetups={meetups} /&gt;
    &lt;/&gt;
  )
}

huangapple
  • 本文由 发表于 2023年6月29日 04:51:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76576630.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定