根据this RFC:
客户端组件可能not导入服务器组件或呼叫服务器 钩子/实用程序,因为它们只在服务器上工作.
我正在从事一个项目使用react 18.2和nextjs v14与应用程序路由.
我有一个我正在处理的页面:
页面是一个客户端组件,因为页面中的几乎所有内容都依赖于客户端功能.
这是一个表单,所以一切都取决于React useState()
钩子.
Page.tsx的实际代码如下所示,它是一个很大的组件,我使用的是一个名为JoyUI的组件库(由MUI提供).
-
重要的部分是我在代码中使用
"use client"
指令的第一行,因为正如我所提到的,该组件(NewModeratorPage)依赖于许多客户端功能. -
要查看的第二部分是
<NewModeratorPage />
组件的Return块中的<SelectCompany />
组件,如下所示:
'use client'
import React from 'react'
import { Grid } from '@mui/material'
import useBreakpoints from '@/hooks/useBreakpoints'
import PasswordInput from '@/components/PasswordInput'
import AvatarUploader from '@/components/AvatarUploader'
import { Stack, Input, FormLabel, Checkbox } from '@mui/joy'
import {
EmailRounded as EmailIcon,
PhoneRounded as PhoneIcon,
PersonRounded as PersonIcon,
} from '@mui/icons-material'
import SelectCompany from './SelectCompany'
const NewModeratorPage = () => {
const { isDownMd } = useBreakpoints()
return (
<Grid container spacing={2}>
<Grid item xs={12} md={3}>
<AvatarUploader placeholder={<PersonIcon sx={{ fontSize: 64 }} />} />
</Grid>
<Grid item xs={12} md={8}>
<Stack spacing={1}>
<FormLabel>Name</FormLabel>
<Stack direction={isDownMd ? 'column' : 'row'} spacing={2}>
<Input placeholder="First name" size="sm" fullWidth required />
<Input placeholder="Last name" size="sm" fullWidth required />
</Stack>
<FormLabel>Credentials</FormLabel>
<Stack direction={isDownMd ? 'column' : 'row'} spacing={2}>
<Input
placeholder="Email"
startDecorator={<EmailIcon />}
type="email"
size="sm"
fullWidth
required
/>
<Input placeholder="Phone number" startDecorator={<PhoneIcon />} size="sm" fullWidth />
</Stack>
<Stack direction={isDownMd ? 'column' : 'row'} spacing={2}>
<PasswordInput size="sm" fullWidth required />
</Stack>
<Checkbox size="sm" label="Send password via email" defaultChecked />
<SelectCompany />
</Stack>
</Grid>
</Grid>
)
}
export default NewModeratorPage
-
<SelectCompany />
等于server component. 它呈现一个<Select>
,其中<Options>
是从API获取的.
因此,<SelectCompany />
涉及数据获取.
这是一个很好的指示符,表明该组件应该是服务器组件.
- 一旦用户请求页面,页面将与表单一起提供,并预取
<SelectCompany/>
个包含所有数据的页面.
因此,没有加载时间来获取客户端的公司.
- 它使用"use server"指令,以表明这是一个服务器组件.
下面是<SelectCompany />
服务器组件的代码.
"use server"
import React, { PropsWithChildren } from 'react'
import { Select, Option, Avatar, Stack } from '@mui/joy'
export interface SelectCompanyProps extends PropsWithChildren {}
const SelectCompany = async ({ children, ...props }: SelectCompanyProps) => {
const response = await fetch('/api/companies')
const data = await response.json()
console.log(data)
return (
<Select value={1}>
<Option value={1}>
<Stack direction="row" spacing={2}>
<Avatar size="sm" />
<React.Fragment>Company 1</React.Fragment>
</Stack>
</Option>
</Select>
)
}
export default SelectCompany
首先,我在浏览器中收到以下错误:
Error: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding `'use client'` to a module that was originally written for the server.
在终端(我使用的是Linux btw)中,我收到以下错误:
Internal error: Error: Server Functions cannot be called during initial render. This would create a fetch waterfall. Try to use a Server Component to pass data to Client Components instead.
据我所知,这个错误的原因是不允许客户端组件导入服务器组件,
那么,我的案件的解决方案是什么?我希望<SelectCompanies />
作为服务器组件.