微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ReactJs,使用HOC作为功能组件的受Typescript保护的路由

如何解决ReactJs,使用HOC作为功能组件的受Typescript保护的路由

我不知道如何构建一个简单的HOC来保护组件,即确保在组件呈现之前用户登录

这是我尝试构建用于保护组件的HOC(尚不起作用)。

export default function ProtectedRoute(Component: React.ComponentType) {
  return () => {
    const authUser = useSession();
    const router = useRouter();

    if (typeof window === 'undefined') {
      return null;
    }

    if (!authUser) {
      router.push('/login');
      return null;
    }
    return <Component />;
  };
}

这是我要保护的组件。

const AppLayout = ({
  children,title = 'This is the default title',}: Props): React.ReactElement => {
return (
     ...
      <main className="bg-nord-bg2">
        <div className="min-h-screen w-full max-w-screen-xl mx-auto py-6 sm:px-6 lg:px-8">
          <Alert />
          {children}
        </div>
      </main>
)
}

export default ProtectedRoute(AppLayout);

这就是我所说的布局组件:

function App({ Component,pageProps }: any) {
  return (
        <Layout title="Meno">
          <Component {...pageProps} />
        </Layout>
      ) 
}

export default App;

这是我的错误消息: Argument of type '({ children,title,}: Props) => React.ReactElement' is not assignable to parameter of type 'ComponentType<{}>'. Type '({ children,}: Props) => React.ReactElement' is not assignable to type 'FunctionComponent<{}>'. Types of parameters '__0' and 'props' are incompatible. Property 'title' is missing in type '{ children?: ReactNode; }' but required in type 'Props'

您对我有什么提示吗?

解决方法

简而言之,您的AppLayout不会返回ReactElement,而是返回FC(功能组件)。

我建议将此cheatsheat用于类型差异。


这是一个有效的示例项目,可以在here中找到。

components / AppContext / index.tsx

import { createContext,useCallback,useContext,useState } from "react";
import type { FC,ReactNode } from "react";

type Context = {
  isAuthenticated: Boolean;
  handleAuthentication: () => void;
}

const AppContext = createContext<Context>({
  isAuthenticated: false,handleAuthentication: () => {},});

const AppContextProvider: FC<{ children: ReactNode }> = ({ children }) => {
  const [isAuthenticated,setAuthentication] = useState(false);

  const handleAuthentication = useCallback(() => {
    setAuthentication((prevState) => !prevState);
  },[]);

  return (
    <AppContext.Provider
      value={{
        isAuthenticated,handleAuthentication,}}
    >
      {children}
      {isAuthenticated && (
        <button type="button" onClick={handleAuthentication}>
          Log out
        </button>
      )}
    </AppContext.Provider>
  );
};

export const useAppContext = () => useContext(AppContext);

export default AppContextProvider;

components / withAuthentication / index.tsx

import { useRouter } from "next/router";
import { useEffect } from "react";
import { useAppContext } from "../AppContext";
import type { FC } from "react";

type withAuthenticationFn = (Component: FC) => FC;

const withAuthentication: withAuthenticationFn = (Component) => {
  const Authenticated: FC = (): JSX.Element | null => {
    const { isAuthenticated } = useAppContext();
    const router = useRouter();

    useEffect(() => {
      if (!isAuthenticated) router.push("/login");
    });

    return isAuthenticated ? <Component /> : null;
  };

  return Authenticated;
};

export default withAuthentication;

页面/_app.tsx

import AppContextProvider from "../components/AppContext";
import type { FC } from "react";
import type { AppProps } from "next/app";

const App: FC<AppProps> = ({ Component,pageProps }) => (
  <AppContextProvider>
    <Component {...pageProps} />
  </AppContextProvider>
);

export default App;

页面/about.tsx

import Head from "next/head";
import Link from "next/link";
import withAuthentication from "../components/withAuthentication";
import type { NextPage } from "next";

const AboutPage: NextPage = () => (
  <>
    <Head>
      <title> About - Next App</title>
    </Head>
    <h1>About</h1>
    <p>This is the about page</p>
    <p>
      <Link href="/">
        <a>Go home</a>
      </Link>
    </p>
  </>
);

export default withAuthentication(AboutPage);

pages / index.tsx

import Link from "next/link";
import Head from "next/head";
import withAuthentication from "../components/withAuthentication";
import type { NextPage } from "next";

const IndexPage: NextPage = () => (
  <>
    <Head>
      <title> Dashboard - Next App</title>
    </Head>
    <h1>Hello Next.js ?</h1>
    <p>
      <Link href="/about">
        <a>About</a>
      </Link>
    </p>
  </>
);

export default withAuthentication(IndexPage);

pages / login.tsx

import Head from "next/head";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { useAppContext } from "../components/AppContext";
import type { NextPage } from "next";

const Login: NextPage = () => {
  const { isAuthenticated,handleAuthentication } = useAppContext();
  const router = useRouter();

  useEffect(() => {
    if (isAuthenticated) router.push("/");
  },[isAuthenticated]);

  return (
    <>
      <Head>
        <title> Login - Next App</title>
      </Head>
      <button type="button" onClick={handleAuthentication}>
        Log in
      </button>
    </>
  );
};

export default Login;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。