跳到内容
+

Next.js App Router

了解如何在 Next.js App Router 中使用 Joy UI。

示例

在一个新的基于 App Router 的项目上从头开始?

通过这个示例:Joy UI - Next.js App Router with TypeScript,直接开始编码。

Next.js 和 React Server Components

Next.js App Router 实现了 React Server Components,React 即将推出的功能

为了支持 App Router,Joy UI 中需要访问浏览器 API 的组件和钩子通过 "use client" 指令导出。

在 App Router 中使用 Joy UI

要设置 Joy UI,创建一个自定义的 ThemeRegistry 组件,它结合了 Emotion CacheProvider、Joy UI 的 CssVarsProvider 和来自 next/navigationuseServerInsertedHTML 钩子,如下所示

// app/ThemeRegistry.tsx
'use client';
import createCache from '@emotion/cache';
import { useServerInsertedHTML } from 'next/navigation';
import { CacheProvider } from '@emotion/react';
import { CssVarsProvider } from '@mui/joy/styles';
import CssBaseline from '@mui/joy/CssBaseline';
import theme from '/path/to/custom/theme'; // OPTIONAL

// This implementation is from emotion-js
// https://github.com/emotion-js/emotion/issues/2928#issuecomment-1319747902
export default function ThemeRegistry(props) {
  const { options, children } = props;

  const [{ cache, flush }] = React.useState(() => {
    const cache = createCache(options);
    cache.compat = true;
    const prevInsert = cache.insert;
    let inserted: string[] = [];
    cache.insert = (...args) => {
      const serialized = args[1];
      if (cache.inserted[serialized.name] === undefined) {
        inserted.push(serialized.name);
      }
      return prevInsert(...args);
    };
    const flush = () => {
      const prevInserted = inserted;
      inserted = [];
      return prevInserted;
    };
    return { cache, flush };
  });

  useServerInsertedHTML(() => {
    const names = flush();
    if (names.length === 0) {
      return null;
    }
    let styles = '';
    for (const name of names) {
      styles += cache.inserted[name];
    }
    return (
      <style
        key={cache.key}
        data-emotion={`${cache.key} ${names.join(' ')}`}
        dangerouslySetInnerHTML={{
          __html: styles,
        }}
      />
    );
  });

  return (
    <CacheProvider value={cache}>
      <CssVarsProvider theme={theme}>
        {/* the custom theme is optional */}
        <CssBaseline />
        {children}
      </CssVarsProvider>
    </CacheProvider>
  );
}

// app/layout.tsx
export default function RootLayout(props) {
  return (
    <html lang="en">
      <body>
        <ThemeRegistry options={{ key: 'joy' }}>{props.children}</ThemeRegistry>
      </body>
    </html>
  );
}

Props 序列化

从服务器组件传递的 Props——例如 page.js 或其他路由文件——必须是可序列化的