Next.js 常见开发问题

2023-11-30 | 23分钟 | yrobot | Next.js,开发,问题,方案

为/api/* 配置跨域

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  async headers() {
    return [
      {
        source: "/api/(.*)",
        headers: [{ key: "Access-Control-Allow-Origin", value: "*" }],
      },
    ];
  },
};

module.exports = nextConfig;

Next.js SSR/SSG theme 逻辑

如果只考虑 SSR,那么将 theme 数据直接存在 cookie 里是最简单的方案。这样在服务端渲染时,可以直接从 cookie 中获取 theme 数据,然后在服务端渲染时,将 theme 数据传递给组件即可。

但是在 SSG 情况下,theme 数据只能存在浏览器环境中,如 localStorage。然而在服务端 SSG 时,无法获取 theme 数据。

所以,只能在浏览器渲染完 html 前,将 theme 数据写入 html 中,用户看到页面第一眼就是正确的 theme。

Next-Themes 可以实现这样的效果:

layout.tsx

import { ThemeProvider } from "next-themes";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body className={inter.className}>
        <ThemeProvider
          attribute="data-theme"
          themes={themes}
          defaultTheme={themes[0]}
          storageKey="theme"
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

查看源码后,next-themes 的方案也是在客户端 html 渲染之前执行一段更新 css theme 变量的 script

处理 Nav 逻辑(怎么处理 Nav 的 active 状态)

问题难点主要是,在 Server 端 和 Client 端,获取的 pathname 是一样。

https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#checking-active-links

直接使用 next/navigation 中的 usePathname 可以解决这个问题。

Nav.tsx

"use client";

import { usePathname } from "next/navigation";
import Link from "next/link";

export function Links() {
  const pathname = usePathname();
  return (
    <nav>
      <ul>
        <li>
          <Link className={`link ${pathname === "/" ? "active" : ""}`} href="/">
            Home
          </Link>
        </li>
        <li>
          <Link
            className={`link ${pathname === "/about" ? "active" : ""}`}
            href="/about"
          >
            About
          </Link>
        </li>
      </ul>
    </nav>
  );
}