服务端组件中使用客户端组件报错,有无解决方案?
问题解决:TonConnectUIProvider在Next.js Layout中报错
createContext is not a function 问题场景
我的src/app/layout.js代码如下:
import * as React from 'react'; import '@/styles/global.css'; import { config } from '@/config'; import { TonConnectUIProvider } from '@tonconnect/ui-react'; export const viewport = { width: 'device-width', initialScale: 1, themeColor: config.site.themeColor, }; export default async function Layout({ children }) { return ( <html lang="en"> <body> <TonConnectUIProvider manifestUrl={process.env.MANIFEST_URL}> {children} </TonConnectUIProvider> </body> </html> ); };
运行后出现错误:
Error: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function
该错误确实是因为TonConnectUIProvider依赖客户端React API(如useState/useEffect/createContext),但当前Layout是Next.js默认的Server Component,无法在服务端执行这些客户端API导致的。
解决办法
方法1:封装TonConnectUIProvider为独立客户端组件
创建单独的客户端组件文件components/TonConnectProvider.jsx:
'use client'; import { TonConnectUIProvider } from '@tonconnect/ui-react'; export default function TonConnectProvider({ children, manifestUrl }) { return ( <TonConnectUIProvider manifestUrl={manifestUrl}> {children} </TonConnectUIProvider> ); }
修改原layout.js,导入并使用这个封装后的组件:
import * as React from 'react'; import '@/styles/global.css'; import { config } from '@/config'; import TonConnectProvider from '@/components/TonConnectProvider'; export const viewport = { width: 'device-width', initialScale: 1, themeColor: config.site.themeColor, }; export default async function Layout({ children }) { return ( <html lang="en"> <body> <TonConnectProvider manifestUrl={process.env.MANIFEST_URL}> {children} </TonConnectProvider> </body> </html> ); };
方法2:直接将Layout标记为客户端组件
如果不需要保持Layout为Server Component,可以直接在文件顶部添加'use client'指令,同时移除async关键字(客户端组件不能是异步函数):
'use client'; import * as React from 'react'; import '@/styles/global.css'; import { config } from '@/config'; import { TonConnectUIProvider } from '@tonconnect/ui-react'; export const viewport = { width: 'device-width', initialScale: 1, themeColor: config.site.themeColor, }; export default function Layout({ children }) { return ( <html lang="en"> <body> <TonConnectUIProvider manifestUrl={process.env.MANIFEST_URL}> {children} </TonConnectUIProvider> </body> </html> ); };
关键说明
- Next.js 13+ App Router中,组件默认是Server Component,无法使用客户端专属React API;
'use client'指令会将组件标记为客户端组件,使其在浏览器端渲染,从而支持所有客户端API;- 方法1更推荐,它能保持Layout的服务端渲染特性,仅隔离需要客户端执行的部分,兼顾性能与功能。
内容的提问来源于stack exchange,提问作者ytpm
相关产品推荐
相关产品推荐

