router.isFallback 将 true 更改为 false

router.isFallback changes true to false

我的环境在这里:

Environment Version
Rails 7.0.0
React 18.0
Next.js 12.1.4

我的getStaticPathsgetStaticProps设置在这里:

export const getStaticPaths = async () => {
  const data = await axios.get(
    `${process.env.NEXT_PUBLIC_ENDPOINT}/admin/users_data`
  );

  const paths = data.data.users.map((user: any) => {
    return { params: { id: user.id.toString() } };
  });
  return {
    paths,
    fallback: true,
  };
};

export const getStaticProps = async (params: any) => {
  const users = params.params.id;
  return {
    props: { users },
    revalidate: 10,
  };
};

我要添加用户,next build后可以访问详情页。
我听说我可以使用 revalidatefallback: true.

来实现它

没有路径我写了一个错误选项

import ErrorPage from "next/error";

export default function UsersDetailPage(props: {
  users: any;
}) {
  const router = useRouter();

  return !router.isFallback && props.users ? (
// UsersDetailPage
  ) : (
    <ErrorPage statusCode={404} />
  );
}

从这段代码直接访问错误的路径,几秒后显示错误页面。
参数是这样的:

props.users: undefined
router.isFallback: true

但之后参数会变成

props.users: example // <-- not existing
router.isFallback: false

并显示详情页。
我不明白这是怎么回事。

你能教我如何解决这个问题吗?
谢谢。

更新

已更新

如果您的路径在 getStaticPaths 中定义但没有来自 API 调用的用户数据,您可以使用 props.user 检查显示 404。使用此解决方案,您可以使用 revalidate: 10fallback: 'blocking' 作为重新验证机制。

import ErrorPage from "next/error";

export default function UsersDetailPage(props: {
  users: any;
}) {

  if(!props.users) {
     return <ErrorPage statusCode={404} />
  }

  return <UsersDetailPage/>
}

如果您的路径在 build-time 期间未定义,并且您严格阻止用户访问 non-defined 路径的请求,您可以设置 fallback: false 服务 404 而不是您的用户配置文件组件

If fallback is false, then any paths not returned by getStaticPaths will result in a 404 page.

export const getStaticPaths = async () => {
  const data = await axios.get(
    `${process.env.NEXT_PUBLIC_ENDPOINT}/admin/users_data`
  );

  const paths = data.data.users.map((user: any) => {
    return { params: { id: user.id.toString() } };
  });
  return {
    paths,
    fallback: false, //if the path is not defined, we will show 404
  };
};

export const getStaticProps = async (params: any) => {
  const users = params.params.id;
  return {
    props: { users },
    revalidate: 10,
  };
};

旧答案

我认为你误解了 fallback: truefallback: 'blocking'

fallback: true 不会 return 404,但会 return 一个预期的后备页面,并稍后生成 HTML (后续请求将使用新生成的 HTML 而不是备用页面)

The paths that have not been generated at build time will not result in a 404 page.

fallback: 'blocking'(仅适用于 Next.js 版本 12+)与 revalidate 一起使用。如果您的路径未定义,它将尝试获取数据并且不会 return 后备页面(类似于 server-side 呈现但缓存您的页面供以后使用)

The paths that have not been generated at build time will not result in a 404 page. Instead, Next.js will SSR on the first request and return the generated HTML.

您可以从 Next.js 12

检查 this release note

Currently, Incremental Static Regeneration with fallback: true renders a fallback state before rendering the page contents on the first request to a page that was not generated yet. To block the page from loading (server-rendering), you would need to use fallback: 'blocking'.

您的代码可能如下所示

export const getStaticPaths = async () => {
  const data = await axios.get(
    `${process.env.NEXT_PUBLIC_ENDPOINT}/admin/users_data`
  );

  const paths = data.data.users.map((user: any) => {
    return { params: { id: user.id.toString() } };
  });
  return {
    paths,
    //fallback: true, //serve the fallback page and then generate HTML later
    fallback: 'blocking', //fetch data first and generate HTML on the server
  };
};

export const getStaticProps = async (params: any) => {
  const users = params.params.id;
  return {
    props: { users },
    revalidate: 10,
  };
};

首先尝试像这样重构您的代码(假设 getStaticPaths 中的回退设置为 true)

import ErrorPage from "next/error";

export default function UsersDetailPage(props: {
  users: any;
}) {
  const router = useRouter();

  if(router.isFallback){
    return <div>Loading...</div>
  }

  return UsersDetailPage;

如果用户数据尚不可用,则结果 router.isFallback 为真。此后,它将显示 Loading div,直到数据可用为止。如果可行,请将 div 更改为您的 ErrorPage。但我建议向用户展示 加载状态 比 404 页面更好。

文档:https://nextjs.org/docs/api-reference/data-fetching/get-static-paths#fallback-pages

我解决了这个问题。
非常感谢@Nick Vu 和@MLDC。
这对我真的很有帮助。

所有bug的原因都在这里:

export const getStaticProps = async (params: any) => {
  const users = params.params.id; // <-- here!!
  return {
    props: { users },
    revalidate: 10,
  };
};

似乎 next.js 必须从 getStaticProps 部分的 server-side 获取数据。
所以我固定为:

export const getStaticProps = async (params: any) => {
  const data = await axios.get(
    `${process.env.NEXT_PUBLIC_ENDPOINT}/admin/user_edit/${params.params.id}`
  );
  //<-- here!
  const users = data.data.user;
  return {
    props: { users },
    revalidate: 10,
  };
};

然后问题就解决了