React 18+Next.js中Chakra UI的JSX标识符错误排查
解决Next.js + React 18 + Chakra UI中"Unexpected token
Stack. Expected jsx identifier"错误 这个错误并非<Stack>组件本身的问题,是代码里的JSX语法错误导致解析器报错定位偏差。具体问题出在<TileBody>内部的<Text>标签闭合错误:
原错误代码片段:
<Text fontSize="sm" mt="30px"> paragraph 2. <Text />
这里误用了自闭合标签<Text />,正确的写法应该是使用闭合标签</Text>。这个语法错误破坏了整个JSX结构,导致解析器误报前面的<Stack>组件存在问题。
修复后的对应代码片段:
<Text fontSize="sm" mt="30px"> paragraph 2. </Text>
修复该标签闭合错误后,<Stack>组件即可正常渲染,无需额外添加外层<>、<div>或<React.Fragment>标签。
以下是修复后的完整页面代码:
import * as React from "react" import { gql } from "@apollo/client" import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Box, Button, Center, Flex, Spinner, Stack, Text, useDisclosure, } from "@chakra-ui/react" import { useDestroyAccountMutation } from "lib/graphql" import { useLogout } from "lib/hooks/useLogout" import { useMe } from "lib/hooks/useMe" import { useMutationHandler } from "lib/hooks/useMutationHandler" import { withAuth } from "components/hoc/withAuth" import { HomeLayout } from "components/HomeLayout" import { ProfileLayout } from "components/ProfileLayout" import { Tile, TileBody, TileFooter, TileHeader, TileHeading } from "components/Tile" const _ = gql` mutation DestroyAccount { destroyAccount } ` function Settings() { const alertProps = useDisclosure() const { me, loading } = useMe() const logout = useLogout() const cancelRef = React.useRef<HTMLButtonElement>(null) const handler = useMutationHandler() const [destroy, { loading: destroyLoading }] = useDestroyAccountMutation() const handleDestroy = () => { return handler(destroy, { onSuccess: () => logout() }) } if (loading) return ( <Center> <Spinner /> </Center> ) if (!me) return null return ( <Stack spacing={6}> <Tile> <TileHeader> <TileHeading>Danger zone</TileHeading> </TileHeader> <TileBody> <> <Text fontSize="sm"> paragraph 1. </Text> <Text fontSize="sm" mt="30px"> paragraph 2. </Text> </> </TileBody> <TileFooter> <Flex w="100%" justify="flex-end"> <Button size="sm" colorScheme="red" isDisabled={destroyLoading} isLoading={destroyLoading} onClick={alertProps.onOpen} > Delete </Button> </Flex> <AlertDialog {...alertProps} motionPreset="slideInBottom" isCentered leastDestructiveRef={cancelRef} > <AlertDialogOverlay> <AlertDialogContent> <AlertDialogHeader fontSize="lg" fontWeight="bold"> Delete account </AlertDialogHeader> <AlertDialogBody>Are you sure? </AlertDialogBody> <AlertDialogFooter> <Button ref={cancelRef} onClick={alertProps.onClose}> Cancel </Button> <Button colorScheme="red" onClick={handleDestroy} isLoading={destroyLoading} isDisabled={destroyLoading} ml={3} > Delete </Button> </AlertDialogFooter> </AlertDialogContent> </AlertDialogOverlay> </AlertDialog> </TileFooter> </Tile> </Stack> ) } Settings.getLayout = (page: React.ReactNode) => ( <HomeLayout> <ProfileLayout>{page}</ProfileLayout> </HomeLayout> ) export default withAuth(Settings)
内容的提问来源于stack exchange,提问作者Mel
相关产品推荐
相关产品推荐

