使用 Typescript 使用 getInitialProps 将 prop 传递到 Next.js 中的每个页面
Posted
技术标签:
【中文标题】使用 Typescript 使用 getInitialProps 将 prop 传递到 Next.js 中的每个页面【英文标题】:Pass prop to every single page in Next.js with getInitialProps using Typescript 【发布时间】:2020-04-27 11:02:35 【问题描述】:我有一个案例,我需要在页面呈现服务器端并使用 Next.js 发回给我之前知道用户是否登录,以避免 UI 中出现闪烁变化。
如果用户已经使用此 HOC 组件登录,我能够弄清楚如何防止用户访问某些页面...
export const noAuthenticatedAllowed = (WrappedComponent: NextPage) =>
const Wrapper = (props: any) =>
return <WrappedComponent ...props />;
;
Wrapper.getInitialProps = async (ctx: NextPageContext) =>
let context = ;
const AppToken = nextCookie(ctx);
if (AppToken)
const decodedToken: MetadataObj = jwt_decode(AppToken);
const isExpired = () =>
if (decodedToken.exp < Date.now() / 1000)
return true;
else
return false;
;
if (ctx.req)
if (!isExpired())
ctx.res && ctx.res.writeHead(302, Location: "/" );
ctx.res && ctx.res.end();
if (!isExpired())
context = ...ctx ;
Router.push("/");
const componentProps =
WrappedComponent.getInitialProps &&
(await WrappedComponent.getInitialProps(ctx));
return ...componentProps, context ;
;
return Wrapper;
;
这很好用。
现在,我如何构建一个类似的 HOC 组件来包装它,比如说“_app.tsx”,这样我就可以通过获取令牌将“userAuthenticated”属性传递给每个页面,并确定它是否过期并且基于该道具,我可以向用户显示正确的 UI,而不会出现那种烦人的闪烁效果?
我希望你能帮我解决这个问题,我尝试以与构建上述 HOC 相同的方式来做,但我做不到,尤其是 Typescript 并没有因为其奇怪的错误而使这变得更容易:( 编辑 ====================================== =======
我能够创建这样的 HOC 组件并将 pro userAuthenticated
传递给这样的每个页面...
export const isAuthenticated = (WrappedComponent: NextPage) =>
const Wrapper = (props: any) =>
return <WrappedComponent ...props />;
;
Wrapper.getInitialProps = async (ctx: NextPageContext) =>
let userAuthenticated = false;
const AppToken = nextCookie(ctx);
if (AppToken)
const decodedToken: MetadataObj = jwt_decode(AppToken);
const isExpired = () =>
if (decodedToken.exp < Date.now() / 1000)
return true;
else
return false;
;
if (ctx.req)
if (!isExpired())
// ctx.res && ctx.res.writeHead(302, Location: "/" );
// ctx.res && ctx.res.end();
userAuthenticated = true;
if (!isExpired())
userAuthenticated = true;
const componentProps =
WrappedComponent.getInitialProps &&
(await WrappedComponent.getInitialProps(ctx));
return ...componentProps, userAuthenticated ;
;
return Wrapper;
;
但是我不得不用这个 HOC 包装每一页,以便将道具 userAuthenticated
传递给我拥有的全局布局,因为我无法用它包装“_app.tsx”类组件,它总是给我一个错误...
这行得通...
export default isAuthenticated(Home);
export default isAuthenticated(about);
但这不是...
export default withRedux(configureStore)(isAuthenticated(MyApp));
因此,必须对每个页面都执行此操作,然后将 prop 传递给每个页面中的全局布局,而不是只在“_app.tsx”中执行一次,这有点烦人。
我猜可能是因为“_app.tsx”是一个类组件,而不是像其他页面那样的函数组件? 我不知道,我只是猜测。
有什么帮助吗?
【问题讨论】:
【参考方案1】:对于那些可能遇到同样问题的人,我能够通过以下方式解决这个问题......
import React from "react";
import App from "next/app";
import Store from "redux";
import Provider from "react-redux";
import withRedux from "next-redux-wrapper";
import ThemeProvider from "styled-components";
import GlobalLayout from "../components/layout/GlobalLayout";
import configureStore from "../store/configureStore";
import GlobalStyle from "../styles/global";
import ToastifyStyle from "../styles/toastify";
import nextCookie from "next-cookies";
import jwt_decode from "jwt-decode";
export interface MetadataObj
[key: string]: any;
const theme =
color1: "#00CC99",
color2: "#CC0000"
;
export type ThemeType = typeof theme;
interface Iprops
store: Store;
userAuthenticated: boolean;
class MyApp extends App<Iprops>
// Only uncomment this method if you have blocking data requirements for
// every single page in your application. This disables the ability to
// perform automatic static optimization, causing every page in your app to
// be server-side rendered.
static async getInitialProps( Component, ctx : any)
let userAuthenticated = false;
const AppToken = nextCookie(ctx);
if (AppToken)
const decodedToken: MetadataObj = jwt_decode(AppToken);
const isExpired = () =>
if (decodedToken.exp < Date.now() / 1000)
return true;
else
return false;
;
if (ctx.isServer)
if (!isExpired())
userAuthenticated = true;
if (!isExpired())
userAuthenticated = true;
return
pageProps: Component.getInitialProps
? await Component.getInitialProps(ctx)
: ,
userAuthenticated: userAuthenticated
;
render()
const Component, pageProps, store, userAuthenticated = this.props;
return (
<Provider store=store>
<ThemeProvider theme=theme>
<>
<GlobalStyle />
<ToastifyStyle />
<GlobalLayout userAuthenticated=userAuthenticated>
<Component ...pageProps />
</GlobalLayout>
</>
</ThemeProvider>
</Provider>
);
export default withRedux(configureStore)(MyApp);
如您所见,我发布了整个 _app.tsx 组件,以便您可以看到我正在使用的包。
我将 next-redux-wrapper
和 styled-components
与 Typescript 一起使用。
我必须将gitInitialProps
中的appContext
设为any
类型,否则将无法正常工作。因此,如果您有更好的type
建议,请告诉我。我尝试使用NextPageContext
类型,但由于某种原因在这种情况下不起作用。
通过该解决方案,我能够了解用户是否经过身份验证,并将道具传递给全局布局,以便我可以在每个页面中使用它,而不必在每个页面中都这样做,而且如果您不希望每次都渲染页眉和页脚,如果它们必须依赖于 userAuthenticated
属性,则可以从中受益,因为现在您只需将页眉和页脚放在 GlobalLayout
组件中即可有userAuthenticated
道具供您使用:D
【讨论】:
我的评论与您的帖子和您的回答无关。我想说,ReactJS
遵循函数式编程或 OOP,但我在您的代码中看到了后端开发的思维方式与 OOP 思想。从另一个组件继承一个新类! ?我以前没见过。
@AmerllicA 我明白你在说什么,我什么都试过了。问题在于 s-s-r,如果我正在使用“创建 React 应用程序”并进行“客户端渲染”,我根本不会这样做,但我无法让它以任何其他方式与 s-s-r 一起工作,它甚至是 Next.js 推荐的方式。以上是关于使用 Typescript 使用 getInitialProps 将 prop 传递到 Next.js 中的每个页面的主要内容,如果未能解决你的问题,请参考以下文章
PAT甲级1077 Kuchiguse (20 分)(cin.ignore()吃掉输入n以后的回车接着用getine(cin,s[i])输入N行字符串)
typescript使用 TypeScript 开发 Vue 组件