簡體   English   中英

使用 Typescript 使用 getInitialProps 將 prop 傳遞到 Next.js 中的每個頁面

[英]Pass prop to every single page in Next.js with getInitialProps using Typescript

我有一個案例,當我需要在頁面被呈現服務器端之前知道用戶是否登錄並使用 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”屬性傳遞給每個頁面,並確定它是否過期並基於那個道具我可以向用戶顯示正確的用戶界面而不會有煩人的閃爍效果?

我希望你能幫我解決這個問題,我試着用我構建上述 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”是一個類組件而不是像其他頁面那樣的功能組件? 我不知道,我只是猜測。

有什么幫助嗎?

對於那些可能遇到同樣問題的人,我能夠解決這個問題如下......

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 組件,以便您可以看到我正在使用的包。

我正在使用帶有 Typescript 的next-redux-wrapperstyled-components

我必須將appContext中的gitInitialProps設為any類型,否則它將無法工作。 因此,如果您有更好的type建議,請告訴我。 我嘗試使用NextPageContext類型,但由於某種原因在這種情況下不起作用。

使用該解決方案,我能夠了解用戶是否已通過身份驗證並將 prop 傳遞給全局布局,以便我可以在每個頁面中使用它,而不必逐頁進行,這也有利於以防萬一如果頁眉和頁腳必須依賴於userAuthenticated道具,您不希望它們每次都被渲染,因為現在您只需將頁眉和頁腳放在GlobalLayout組件中,並且仍然可以使用userAuthenticated道具:D

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM