如何解决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 举报,一经查实,本站将立刻删除。