Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
zation opened this issue Jan 2, 2024 · 7 comments

Comments

@zation
Copy link

zation commented Jan 2, 2024

比如说,把项目中的 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
Copy link
Member

MadCcc commented Jan 3, 2024

ConfigProvider 要放在 Registry 下面

@zation
Copy link
Author

zation commented Jan 3, 2024

ConfigProvider 要放在 Registry 下面

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

@MadCcc
Copy link
Member

MadCcc commented Jan 5, 2024

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

@yc-w-cn
Copy link

yc-w-cn commented Jan 10, 2024

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

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

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

参考资料:
mui/material-ui#40214 (comment)

@liaoyio
Copy link

liaoyio commented Jan 12, 2024

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

PS:因为我的项目还集成了 tailwindcss,当我加入 use client,以为一切都将会正常的时候,又回到如何解决 Tailwind 的基本样式覆盖了antd组件库样式的循环。我再次回到了下面这个issuc页面,ant-design/ant-design#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
Copy link
Member

MadCcc commented Jan 12, 2024

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

@zation
Copy link
Author

zation commented Jan 15, 2024

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

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

Li-Ninja added a commit to Li-Ninja/table-tennis that referenced this issue May 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants