Typescript를 사용하여 getInitialProps를 사용하여 Next.js의 모든 단일 페이지에 소품 전달


10

UI에서 깜박임이 발생하지 않도록 페이지가 서버 측으로 렌더링되고 Next.js를 사용하여 나에게 다시 전송되기 전에 사용자가 로그인했는지 여부를 알아야하는 경우가 있습니다.

이 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"prop를 모든 단일 페이지에 전달하여 토큰을 가져 와서 만료 여부에 따라 알아낼 수 있습니다. 그 소품 나는 성가신 깜박임 효과없이 사용자에게 적절한 UI를 보여줄 수 있습니까?

나는 당신이 그것을 도울 수 있기를 희망합니다. 위의 HOC를 구축 한 것과 같은 방식으로 시도했지만 그것을 할 수 없었습니다. 특히 Typescript가 이상한 오류로 이것을 쉽게 만들지 못했습니다 :(


Edit == ===========================================

그런 HOC 구성 요소를 만들고이 같은 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;
};

그러나 userAuthenticated"_app.tsx"클래스 컴포넌트를 랩핑 할 수 없었기 때문에 소품 을 가지고있는 전역 레이아웃으로 소품을 전달하기 위해이 HOC로 모든 단일 페이지를 랩핑 해야했습니다. 항상 오류가 발생합니다. ..

이것은 작동합니다 ...

export default isAuthenticated(Home);
export default isAuthenticated(about);

그러나 이것은 ...

export default withRedux(configureStore)(isAuthenticated(MyApp));

따라서 각 페이지마다이 작업을 수행 한 다음 "_app.tsx"에서 한 번만 수행하는 대신 각 페이지의 전역 레이아웃으로 소품을 전달해야합니다.

"_app.tsx"가 클래스 구성 요소이고 나머지 페이지와 같은 함수 구성 요소가 아니기 때문일 수 있습니다. 모르겠어요, 그냥 추측하고 있습니다.

그것에 대한 도움이 있습니까?

답변:


5

같은 문제가 발생할 수있는 사람들을 위해 다음과 같이 해결할 수있었습니다 ...

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-wrapper하고 styled-components있습니다.

나는했습니다 appContext에서이 gitInitialProps유형의로 any, 그렇지 않으면 작동하지 않습니다. 더 나은 type제안이 있으시면 알려주십시오. type을 사용하려고했지만 NextPageContext이 경우 어떤 이유로 작동하지 않았습니다.

그리고 그 솔루션을 통해 사용자가 인증되었는지 여부를 알 수 있고 전역 레이아웃에 소품을 전달하여 모든 페이지에서 사용할 수 있으며 페이지 당 페이지를 수행하지 않고도 사용할 수 있으며 userAuthenticated소품 에 의존해야 할 때마다 머리글과 바닥 글이 렌더링되는 것을 원하지 않습니다. 이제 머리글과 바닥 글을 GlobalLayout구성 요소에 넣고 userAuthenticated소품을 자유롭게 사용할 수 있기 때문에 : D


내 의견은 게시물 및 답변과 관련이 없습니다. 나는 말을하고 싶지 ReactJS기능적 프로그래밍이나 OOP 다음,하지만 난 OOP의 생각과 당신의 코드에서 백엔드 개발의 사고 방식을 참조하십시오. 다른 컴포넌트에서 새 클래스를 상속하십시오! 😐 (은)는 이전처럼 보지 못했습니다.
AmerllicA

1
@AmerllicA 나는 당신이 말하는 것을 얻었습니다. 나는 모든 것을 시도했습니다. 문제는 SSR과 관련이 있습니다. "Create React App"으로 작업하고 "Client-Side Rendering"을 수행하면 전혀하지 않지만 SSR과는 다른 방식으로 작동하지 않습니다. Next.js에서 권장하는 방식입니다.
루비
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.