next.js 如果用户通过身份验证,则呈现一个页面,

zazmityj  于 2022-11-23  发布在  其他
关注(0)|答案(1)|浏览(239)

我试图弄清楚如何设置一个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"
        }
    ]
}]
1mrurvl1

1mrurvl11#

在您尝试的解决方案中,最后一个几乎是正确的。您的路径是正确的,即**如果用户通过身份验证,您应该将其重定向到/dash页面。**但您是在组件的return语句中进行重定向的,这不是您希望执行任何副作用逻辑的地方。
您的尝试:

import Router from 'next/router';

{me?  Router.push('/dash') : (
   <HomeLayout><LandingPage /></HomeLayout>
)}

将无法运作,因为Router.push会传回<Promise<boolean>>
不要忘记React组件必须返回React元素。在您的情况下,当用户通过身份验证时,您返回的是一个承诺,而不是React元素。
所以你的重定向(这是一个副作用)应该在一个useEffect钩子内完成。
为了解决这个问题,Next文档提供了一个清晰的示例,说明如何正确地执行此操作。您要查找的是本节的最后一个代码块(就在本节前面的代码块)。
不要忘记通过next/router提供的useRouter钩子使用有效的router示例。
因此,您的代码现在变成如下所示:

import { useEffect } from 'react';
import { useRouter } from 'next/router';

// Whatever Component you were doing the redirect
const export YourComponent = () => {
    // your component hooks and states
    const { me, loading } = useMe();
    const router = useRouter();

    // Here is what you were missing
    useEffect(() => {
        if (me) {
            router.push('/dash');
        }
    }, [me]);

    // you can add a loader like you did before
    return loading ? (
        <Center><Spinner /></Center>
    ) : (
        <HomeLayout><LandingPage /></HomeLayout>
    );
};

应该够你找到你要找的东西了。

作为补充说明,您的第一个解决方案是:

{me? 
    <Dash /> // Dash is defined as a page in the pages folder at dash/index
    ///<AuthedHomeLayout><DashLayout /></AuthedHomeLayout> 
: (
    <HomeLayout><LandingPage /></HomeLayout>
)}

无法工作,因为<Dash />是一个下一页,它与基于其文件名的路由相关联。您可以将其视为入口点。

相关问题