webpack 如何在React服务器组件中使用react客户端子组件?

sxissh06  于 2023-10-19  发布在  Webpack
关注(0)|答案(2)|浏览(163)

我正在使用Next.JS 13.4.19和新的app文件夹来启用React服务器组件,并在尝试使用客户端子组件时遇到问题(即<ClientComponent.SubComponent \>)在服务器组件中。
ClientTest.jsx是一个附加了子组件的客户端组件(假设这是一个客户端组件)

'use client'

export default function ClientTest() {
  return <div>ClientTest</div>
}

ClientTest.Item = function ClientTestItem() {
  return <div>ClientTest.Item</div>
}

page.jsx是一个React服务器组件(允许访问数据库或文件系统)

import ClientTest from './ClientTest'

export default function Page() {
  // ClientTest.Item is undefined, and the following line errors with:
  // Unsupported Server Component type: undefined
  return (
    <ClientTest.Item />
  );
}

似乎主要组件<ClientTest />工作正常,但附加的<ClientTest.Item />是未定义的:(
https://codesandbox.io/p/sandbox/currying-grass-wsvtn4?file=/app/page.tsx
可能的解决方法是通过制作另一个 Package 器客户端组件来简单地避免服务器组件中的子组件(在客户端组件中导入ClientTest.Item可以正常工作),但我更希望通过一些神奇的webpack配置来解决这个问题。或者可能是next.js中的一个bug?
供记录在案;在server组件中导入server子组件可以正常工作,在client组件中导入client子组件也可以正常工作。

编辑:

我正在开发一个组件库,它使用了相当多的子组件模式,所以这对我来说是一个“按预期工作”的服务器组件设计部分,还是一个“当前实现限制”/bug,这有很大的区别。
如果这是一个 * 永久 * 的设计限制,我们可能需要重新考虑我们的整个命名方案和架构,以避免可怕的DX,但我还没有发现任何结论,这在React文档。

rkue9o1l

rkue9o1l1#

你做的一切都是正确的,这就是Next.js的问题。我只是对这种行为做了一个宽泛的解释。请参见https://stackoverflow.com/a/77077564/9047572
TL:DR:您需要“use client”指令来使用仅限客户端的特性。一旦组件成为客户端,其嵌套组件也是客户端的。无法更改或拦截此行为。

flmtquvp

flmtquvp2#

我已经为我的案例找到了一个更好的解决方案(作为库作者,他需要发布暴露给服务器组件的客户端子组件),并将其发布在这里,以防有人遇到同样的问题;
我可以在单独的文件中附加和重新导出子组件,而不是使用use client将子组件附加到组件文件中。使用index.js文件,我可以保持消费者的导入路径相同,并且由于此文件没有'use client'指令,因此在导入到React服务器组件时会正确解析:
ClientTest/ClientTest.jsx

'use client'

export default function ClientTest() {
  return <div>ClientTest</div>
}

ClientTest/ClientTest.Item.jsx

'use client'

export default function ClientTestItem() {
  return <div>ClientTest.Item</div>
}

ClientTest/index.js(注意此文件中没有'use client'

import ClientTest from "./ClientTest";
import ClientTestItem from "./ClientTest.Item";

ClientTest.Item = ClientTestItem

export default ClientTest

page.jsx与以前一样,但现在应该可以正常工作

import ClientTest from './ClientTest' // now uses ClientTest/index.js

export default function Page() {
  return (
    <ClientTest.Item />
  );
}

更新的codesandbox:
https://codesandbox.io/p/sandbox/eloquent-hooks-x3qgl8?file=/app/ClientTest/index.ts

相关问题