ant-design / antd-style

css-in-js library with antd v5 token system
https://ant-design.github.io/antd-style/
MIT License
187 stars 29 forks source link

🧐[问题]在Nextjs13中按照文档中【SSR集成】中描述的方式使用,在通过createStyles写样式时会报错 #116

Closed ISproutNew closed 8 months ago

ISproutNew commented 8 months ago

🧐 问题描述

在Next13通过App Router的方式创建的应用,按照文档说明创建了一个StyleRegistry组件并且在 app/layout.tsx中引入

import StyleRegistry from './StyleRegistry';

const RootLayout = ({ children }: PropsWithChildren) => (
  <html lang="en">
    <body>
      <StyleRegistry>{children}</StyleRegistry>
    </body>
  </html>
);

然后在 app/page.tsx文件中

import { createStyles } from "antd-style";

const useStyles = createStyles(({ css }) => {
    return {
        main: css`
            width: 100vw;
            height: 100vh;
        `,
    };
});

export default function Home() {
    const { styles } = useStyles();
    return <main className={styles.main}>my home</main>;
}

产生的报错内容如下:

Error: createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component

在app/page.tsx文件的头部添加 "use client" 就不会报错了。

并且我尝试在其他路由页面例如: app/about/page.tsx 使用createStyles书写样式也会得到同样的报错(不添加"use client"的情况下)。

是我使用的方式不对吗?还是说必须要添加"use client" ,我理解如果要添加"use client"那就意味着整个应用都是客户端组件了🤔

💻 示例代码

src/lib/StyleRegistry.tsx

"use client";

import { StyleProvider, extractStaticStyle } from "antd-style";
import { useServerInsertedHTML } from "next/navigation";
import { PropsWithChildren, useRef } from "react";

const StyleRegistry = ({ children }: PropsWithChildren) => {
    const isInsert = useRef(false);

    useServerInsertedHTML(() => {
        // 避免多次渲染时重复插入样式
        // refs: https://github.com/vercel/next.js/discussions/49354#discussioncomment-6279917
        if (isInsert.current) return;

        isInsert.current = true;

        const styles = extractStaticStyle("").map(item => item.style);

        return <>{styles}</>;
    });

    return (
        <StyleProvider cache={extractStaticStyle.cache}>{children}</StyleProvider>
    );
};

export default StyleRegistry;

src/app/layout.tsx

import Layout from "@/components/Layout";
import StyledComponentsRegistry from "@/lib/StyleRegistry";
import { ThemeToken } from "@/types/theme";

declare module "antd-style" {
    export interface CustomToken extends ThemeToken {}
}

// Font files can be colocated inside of `app`

export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {
    return (
        <html>
            <body>
                <StyledComponentsRegistry>
                    <Layout>{children}</Layout>
                </StyledComponentsRegistry>
            </body>
        </html>
    );
}

src/app/page.tsx

import { createStyles } from "antd-style";

const useStyles = createStyles(({ css }) => {
    return {
        main: css`
            width: 100vw;
            height: 100vh;
        `,
    };
});

export default function Home() {
    const { styles } = useStyles();
    return <main className={styles.main}>my home</main>;
}

🚑 其他信息

image
arvinxx commented 8 months ago

是我使用的方式不对吗?还是说必须要添加"use client" ,我理解如果要添加"use client"那就意味着整个应用都是客户端组件了🤔

目前 CSSinJS 都是客户端渲染,所以必须要加 'use client' 的