我试图弄清楚如何设置一个nextjsindex.tsx页面,如果用户通过身份验证,则呈现一个页面,如果用户未通过身份验证,则呈现另一个组件。
我可以正确地呈现未验证的组件,但不能正确地呈现已验证的页面。我找不到教程来解释如何在if语句中放置页面,以便在有已验证用户的情况下,主nextjs index.tsx页面呈现我指定的页面。
我有一个index.tsx,页面中包含:
import * as React from "react"
import { Box, Center, Spinner, VStack } from "@chakra-ui/react"
import Head from "next/head"
// import NextLink from "next/link"
import { useMe } from "lib/hooks/useMe"
import { DashLayout } from "components/DashLayout"
import { AuthedHomeLayout } from "components/AuthedHomeLayout"
import LandingPage from "components/landing/lp"
import { HomeLayout } from "components/HomeLayout"
export default function Home() {
const { me, loading } = useMe()
if (loading)
return (
<Center>
<Spinner />
</Center>
)
return (
<Box>
<Head>
<title>test</title>
</Head>
<Center flexDir="column" w="100%">
<VStack>
{me? <AuthedHomeLayout><DashLayout /></AuthedHomeLayout> : (
<HomeLayout><LandingPage /></HomeLayout>
)}
</VStack>
</Center>
</Box>
)
}
当我以经过身份验证的用户身份尝试此操作时,DashLayout确实加载了,但其中的链接没有呈现。
DashLayout中有一组链接,这些链接构成 Jmeter 板的页面:
import * as React from "react"
import { Box, Flex, Heading, Link, LinkProps, Stack, useColorModeValue } from "@chakra-ui/react"
import NextLink from "next/link"
import { useRouter } from "next/router"
const DashLayout: React.FC = ({ children }) => {
return (
<Box pt={10} pb={20} w="100%">
<Flex flexWrap={{ base: "wrap", md: "unset" }}>
<Box pos="relative">
<Stack
position="sticky"
top="100px"
minW={{ base: "unset", md: "200px" }}
mr={8}
flexDir={{ base: "row", md: "column" }}
mb={{ base: 8, md: 0 }}
spacing={{ base: 0, md: 4 }}
>
<ProfileLink href="/dash">Dashboard</ProfileLink>
<ProfileLink href="/dash/library">Library</ProfileLink>
<ProfileLink href="/dash/help">Help</ProfileLink>
</Stack>
</Box>
<Box w="100%">{children}</Box>
</Flex>
</Box>
)
}
export default DashLayout
interface ProfileLinkProps extends LinkProps {
href: string
}
const ProfileLink: React.FC<ProfileLinkProps> = ({ href, ...props }) => {
const { asPath } = useRouter()
const isActive = asPath === href
const activeColor = useColorModeValue("black", "white")
const inactiveColor = useColorModeValue("gray.600", "gray.500")
return (
<NextLink href={href} passHref>
<Link
pr={4}
h="25px"
justifyContent={{ base: "center", md: "flex-start" }}
textDecoration="none !important"
color={isActive ? activeColor : inactiveColor}
_hover={{ color: useColorModeValue("black", "white") }}
fontWeight={isActive ? "semibold" : "normal"}
>
{props.children}
</Link>
</NextLink>
)
}
如果有身份验证用户,则要呈现的页面为:
import * as React from "react"
import { gql } from "@apollo/client"
import { Center, Spinner, Stack, Text } from "@chakra-ui/react"
import { useUpdateMeMutation } from "lib/graphql"
import { useForm } from "lib/hooks/useForm"
import { useMe } from "lib/hooks/useMe"
import { useMutationHandler } from "lib/hooks/useMutationHandler"
import { UPLOAD_PATHS } from "lib/uploadPaths"
import Yup from "lib/yup"
import { ButtonGroup } from "components/ButtonGroup"
import { Form } from "components/Form"
import { withAuth } from "components/hoc/withAuth"
import { AuthedHomeLayout } from "components/AuthedHomeLayout"
import { ImageUploader } from "components/ImageUploader"
import { Input } from "components/Input"
import { DashLayout } from "components/DashLayout"
const _ = gql`
mutation UpdateMe($data: UpdateUserInput!) {
updateMe(data: $data) {
...Me
}
}
`
const ProfileSchema = Yup.object().shape({
email: Yup.string().email().required("Required").nullIfEmpty(),
firstName: Yup.string().required("Required").nullIfEmpty(),
lastName: Yup.string().required("Required").nullIfEmpty(),
})
function Dash() {
const { me, loading } = useMe()
const handler = useMutationHandler()
const [updateUser] = useUpdateMeMutation()
const updateAvatar = (avatar: string | null) => {
return handler(() => updateUser({ variables: { data: { avatar } } }), {
onSuccess: (_, toast) => toast({ description: "Avatar updated." }),
})
}
const defaultValues = {
email: me?.email || "",
firstName: me?.firstName || "",
lastName: me?.lastName || "",
}
const form = useForm({ defaultValues, schema: ProfileSchema })
const handleUpdate = (data: typeof defaultValues) => {
return form.handler(() => updateUser({ variables: { data } }), {
onSuccess: (_, toast) => {
toast({ description: "Info updated!" })
form.reset(data)
},
})
}
if (loading)
return (
<Center>
<Spinner />
</Center>
)
if (!me) return null
return (
<Stack spacing={6}>
<Tile>
<Text>alskjf</Text>
</Tile>
</Stack>
)
}
Dash.getLayout = (page: React.ReactNode) => (
<AuthedHomeLayout>
<DashLayout>{page}</DashLayout>
</AuthedHomeLayout>
)
export default withAuth(Dash)
我还尝试将index.tsx条件定义为:
{me?
<Dash /> // Dash is defined as a page in the pages folder at dash/index
///<AuthedHomeLayout><DashLayout /></AuthedHomeLayout>
: (
<HomeLayout><LandingPage /></HomeLayout>
)}
如何定义index.tsx,以便在有授权用户的情况下呈现一个页面,而在没有授权用户的情况下呈现另一个页面?
我看到了this post,并尝试使用它提出的一个建议,如下所示:
import Router from 'next/router';
{me? Router.push('/dash') : (
<HomeLayout><LandingPage /></HomeLayout>
)}
当我尝试这样做时,我得到如下错误:
[{
"resource": "/src/pages/index.tsx",
"owner": "typescript",
"code": "2322",
"severity": 8,
"message": "Type 'Element | Promise<boolean>' is not assignable to type 'ReactNode'.\n Type 'Promise<boolean>' is not assignable to type 'ReactNode'.",
"source": "ts",
"startLineNumber": 32,
"startColumn": 13,
"endLineNumber": 34,
"endColumn": 15,
"relatedInformation": [
{
"startLineNumber": 1360,
"startColumn": 9,
"endLineNumber": 1360,
"endColumn": 17,
"message": "The expected type comes from property 'children' which is declared here on type 'IntrinsicAttributes & OmitCommonProps<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof StackProps> & StackProps & { ...; }'",
"resource": "repo/node_modules/@types/react/index.d.ts"
}
]
}]
1条答案
按热度按时间1mrurvl11#
在您尝试的解决方案中,最后一个几乎是正确的。您的路径是正确的,即**如果用户通过身份验证,您应该将其重定向到
/dash
页面。**但您是在组件的return语句中进行重定向的,这不是您希望执行任何副作用逻辑的地方。您的尝试:
将无法运作,因为
Router.push
会传回<Promise<boolean>>
。不要忘记React组件必须返回React元素。在您的情况下,当用户通过身份验证时,您返回的是一个承诺,而不是React元素。
所以你的重定向(这是一个副作用)应该在一个
useEffect
钩子内完成。为了解决这个问题,Next文档提供了一个清晰的示例,说明如何正确地执行此操作。您要查找的是本节的最后一个代码块(就在本节前面的代码块)。
不要忘记通过next/router提供的
useRouter
钩子使用有效的router
示例。因此,您的代码现在变成如下所示:
应该够你找到你要找的东西了。
作为补充说明,您的第一个解决方案是:
无法工作,因为
<Dash />
是一个下一页,它与基于其文件名的路由相关联。您可以将其视为入口点。