【问题标题】:Default dynamic route in Next.jsNext.js 中的默认动态路由
【发布时间】:2021-06-21 17:18:00
【问题描述】:

Next.js 使我们能够使用方括号 [param] 在我们的应用程序中定义动态路由。它允许我们以例如语言作为参数传递的方式设计 URL。当没有路由匹配时,用户被重定向到错误页面。

这个想法很简单,Next.js 中与动态路由相关的文档是rather limited。有人知道是否可以为动态路由参数分配默认值吗?

【问题讨论】:

  • 您能否阐明“为动态路由参数分配默认值”的意思?实际用例是什么?
  • 你有什么想法?如果用户转到/foo/check/,您将重定向到/foo/check/1(考虑1 作为您的默认值),或者如果用户转到/foo/check/876(考虑876 超出范围值)您重定向到/foo/check/1?跨度>
  • @PedroHenrique 是的,你的第一个例子。假设我们有国家和语言路由参数 -/foo/[country]/[language]。如果默认语言为“en”,我们希望在用户导航到/foo/[country]/(比如说/foo/UK/)时将此值传递给路由器

标签: reactjs next.js url-routing


【解决方案1】:

有关于 i18n routingredirects 的文档页面以及对 locale 参数的特殊支持(我个人没有使用过)。

在更一般的意义上,听起来你想要的是optional catch all routes

您可以在foo 目录中定义一个名为[[...slug]].js 的文件。与/foo/us/en 之类的路径对应的params{ slug: ["us", "en"] },其中路径的每一段都成为slug 数组的一个元素。

您可以使用getStaticPaths 生成所有已知的国家/语言对。设置fallback: true 允许用户输入另一个组合并且不会得到 404。

export const getStaticPaths = async () => {
  return {
    paths: [
      { params: { slug: ["us", "en"] } },
      { params: { slug: ["us", "es"] } },
      { params: { slug: ["ca", "en"] } },
      { params: { slug: ["ca", "fr"] } },
      /*...*/
    ],
    fallback: true, // allows unknown
  };
};

就重定向而言,这取决于您是否需要实际的重定向,例如输入/foo 会导致/foo/us/en,或者它们是否是显示相同内容的两个单独页面。我假设我们想要一个实际的重定向。

您将在 getStaticProps 函数中从 slug 转换为 props。这也是您实施重定向的地方。我将假设您拥有(或可以创建)一些实用函数,例如 isValidCountry(country)getDefaultLanguage(country)

export const getStaticProps = async ( context ) => {
  const [country, language] = context.params?.slug ?? [];

  // if there is no country, go to us/en
  if (!country || !isValidCountry(country)) {
    return {
      redirect: {
        statusCode: 301, // permanent redirect
        destination: "/foo/us/en",
      },
    };
  }

  // if there is no language, go to the default for that country
  if (!language || !isValidLanguage(language, country)) {
    return {
      redirect: {
        statusCode: 301, // permanent redirect
        destination: `/foo/${country}/${getDefaultLanguage(country)}`,
      },
    };
  }

  // typical case, return country and language as props
  return {
    props: {
      country,
      language,
    },
  };
};

您可以使用useRouterisFallback 在组件本身中执行某些操作,但我不确定是否需要。在开发模式下,至少我得到了正确的重定向。

  • /foo/ca/en - 好的
  • /foo/ca/fr - 好的
  • /foo/ca/xx - 重定向到 /foo/ca/en
  • /foo/ca - 重定向到 /foo/ca/en
  • /foo - 重定向到 /foo/us/en

带有 TypeScript 类型的完整代码:

import { GetStaticPaths, GetStaticProps } from "next";

export interface Props {
  country: string;
  language: string;
}

export default function Page({ country, language }: Props) {
  return (
    <div>
      <h1>
        {country} - {language}
      </h1>
    </div>
  );
}

const pairs = [
  ["us", "en"],
  ["us", "es"],
  ["ca", "en"],
  ["ca", "fr"],
];

const isValidCountry = (c: string) => pairs.some(([cc]) => cc === c);
const isValidLanguage = (l: string, c: string) =>
  pairs.some(([cc, ll]) => cc === c && ll === l);
const getDefaultLanguage = (c: string) =>
  pairs.find(([cc]) => cc === c)?.[1] ?? "en";

export const getStaticProps: GetStaticProps<Props, { slug: string[] }> = async (
  context
) => {
  const [country, language] = context.params?.slug ?? [];

  // if there is no country, go to us/en
  if (!country || !isValidCountry(country)) {
    return {
      redirect: {
        statusCode: 301, // permanent redirect
        destination: "/foo/us/en",
      },
    };
  }

  // if there is no language, go to the default for that country
  if (!language || !isValidLanguage(language, country)) {
    return {
      redirect: {
        statusCode: 301, // permanent redirect
        destination: `/foo/${country}/${getDefaultLanguage(country)}`,
      },
    };
  }

  // typical case, return country and language as props
  return {
    props: {
      country,
      language,
    },
  };
};

export const getStaticPaths: GetStaticPaths<{ slug: string[] }> = async () => {
  return {
    paths: pairs.map((slug) => ({
      params: { slug },
    })),
    fallback: true, // allows unknown
  };
};

【讨论】:

  • 感谢琳达的全面回答!
猜你喜欢
  • 2022-11-05
  • 2020-09-08
  • 1970-01-01
  • 2023-03-09
  • 2021-11-18
  • 2022-01-10
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
相关资源
最近更新 更多