ant-design / nextjs-registry

Style registry of Ant Design for Nextjs
15 stars 3 forks source link

在 layout 中使用 config provider,并且页面中有 server component 用了 antd 就会报错 #1

Open zation opened 9 months ago

zation commented 9 months ago

比如说,把项目中的 example/with-app-router 改一下:

// app/layout.tsx

import React from 'react'
import { AntdRegistry } from '@ant-design/nextjs-registry'
import {
  ConfigProvider,
} from 'antd'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <ConfigProvider>
          <AntdRegistry>
            {children}
          </AntdRegistry>
        </ConfigProvider>
      </body>
    </html>
  )
}
// app/page.tsx

import React from 'react';
import {
  Button,
} from 'antd'

const Page: React.FC = () => (
    <Button>123</Button>
);

export default Page;

这样就会报错Error: Element type is invalid. Received a promise that resolves to: undefined. Lazy element type must resolve to a class or function.

MadCcc commented 9 months ago

ConfigProvider 要放在 Registry 下面

zation commented 9 months ago

ConfigProvider 要放在 Registry 下面

放下面还是一样的报错,你试试呢

MadCcc commented 9 months ago

确实有问题,目前的 workaround 是把 ConfigProvider 封装一下,加上 use client 即可。 这个问题应该是 ConfigProvider 的。

yc-w-cn commented 8 months ago

没有使用 ConfigProvider,遇到了同样的问题,放 Button 组件正常,换了一个 Divider 组件,就有这个错误。 目前的解决办法是:用具体的路径引用代替原先的引用方式。

// 现在的方式
import Divider from "antd/es/divider"; 

// 原先的方式
import { Divider } from "antd";

参考资料: https://github.com/mui/material-ui/issues/40214#issuecomment-1881674291

liaoyio commented 8 months ago

官网示例的问题,看到新的导入方法赶紧换成使用 @ant-design/nextjs-registry 的方式集成 antd,本来以为可以不用使用use client 了,结果被坑了一波。

PS:因为我的项目还集成了 tailwindcss,当我加入 use client,以为一切都将会正常的时候,又回到如何解决 Tailwind 的基本样式覆盖了antd组件库样式的循环。我再次回到了下面这个issuc页面,https://github.com/ant-design/ant-design/issues/38794,是的,这让我不得不重新下载 @ant-design/cssinjs,并且使用 StyleProvider方式去解决。

下面示例是我在项目中使用 @ant-design/nextjs-registry 时用法:

可以新建一个 AntdConfigProvider.tsx 文件:

"use client"

import React from "react";
import { ConfigProvider } from "antd";
import en_US from "antd/locale/en_US";
import type { ThemeConfig } from "antd";

# 为了解决 Tailwind 的基本样式覆盖了antd组件库样式
import { StyleProvider } from "@ant-design/cssinjs"

const theme: ThemeConfig = {
  token: {
    fontSize: 14,
    colorPrimary: "#10b981",
  },
  components: {
    Button: {
      fontWeight: 400,
    },
  },
};

const AntdConfigRegistry = ({ children }: React.PropsWithChildren) => {
  return (
    <ConfigProvider locale={en_US} theme={theme}>

      <StyleProvider hashPriority="high">
        {children}
      </StyleProvider>

    </ConfigProvider>
  );
};

export default AntdConfigRegistry;

然后再 layout.tsx 中使用

// App Router 使用 Antd: https://ant-design.antgroup.com/docs/react/use-with-next-cn#%E4%BD%BF%E7%94%A8-app-router
import { AntdRegistry } from "@ant-design/nextjs-registry";
import AntdConfigProvider from "@/components/AntdConfigProvider";
import "@/styles/globals.css";

export const metadata = {
  title: "Next.js"
};

const RootLayout = ({ children }: { children: React.ReactNode }) => {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <AntdRegistry>
            <AntdConfigProvider>
              {children}
            </AntdConfigProvider>
        </AntdRegistry>
      </body>
    </html>
  );
};

export default RootLayout;

在加载页面时,又给我整无语了,闪屏的问题又来了!!!!

😐 算了,不折腾了,我还是退回之前集成的方法吧,如果是我使用姿势不对,欢迎各位大佬批评指正 🫡

参考代码如下:

新建 AntdRegistry.tsx 组件:

"use client";

import React from "react";
import { useServerInsertedHTML } from "next/navigation";
import { createCache, extractStyle, StyleProvider } from "@ant-design/cssinjs";
import type Entity from "@ant-design/cssinjs/es/Cache";
import { ConfigProvider } from "antd";
import en_US from "antd/locale/en_US";

const theme: ThemeConfig = {
  token: {
    colorPrimary: "#10b981",
  }
};

const AntdRegistry = ({ children }: React.PropsWithChildren) => {
  const isServerInserted = React.useRef<boolean>(false);
  const cache = React.useMemo<Entity>(() => createCache(), []);

  useServerInsertedHTML(() => {
    // 避免 css 重复插入
    if (isServerInserted.current) {
      return;
    }
    isServerInserted.current = true;
    return (
      <style
        id="antd"
        dangerouslySetInnerHTML={{ __html: extractStyle(cache, true) }}
      />
    );
  });
  return (
    <StyleProvider cache={cache}>
      <ConfigProvider locale={en_US} theme={theme}>
        {children}
      </ConfigProvider>
    </StyleProvider>
  );
};

layout.tsx 中注册

import AntdRegistry from "@/components/AntdRegistry";
import "@/styles/globals.css";

export const metadata = {
  title: "Next.js"
};

const RootLayout = ({ children }: { children: React.ReactNode }) => {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <AntdRegistry>
           {children}
        </AntdRegistry>
      </body>
    </html>
  );
};

export default RootLayout;
MadCcc commented 8 months ago

@liaoyio 这个包是为了帮助用户踩坑用的,基本实现也是这些,有问题可以直接在这个包里解决,不用多次更新 antd 的文档与 example 了。 至于这个问题我目前没什么头绪,似乎这个包里也做不了什么。

zation commented 8 months ago

@liaoyio 这个包是为了帮助用户踩坑用的,基本实现也是这些,有问题可以直接在这个包里解决,不用多次更新 antd 的文档与 example 了。 至于这个问题我目前没什么头绪,似乎这个包里也做不了什么。

看样子是 antd 的 provider 没有 use client 造成的,要不把 and 的 provider 在这个库里面封装一下,加上 use client?