I want to use getServerSideProps instead of getInitialProps in Next.js+TypeScript, but I don't know how to write it.

Asked 2 years ago, Updated 2 years ago, 134 views

I asked the same question in teratail, but after 2 weeks, I still have 0 answers, so I would like to ask you a question.
I don't care which way you answer.Also, I will share the progress with both of them.Thank you for your cooperation.

Question

To study Next.js+TypeScript, we are trying to modify the repository below.
https://github.com/jasonraimondi/nextjs-jwt-example
I didn't know how to write getServerSideProps in Component, so I got stuck.

Problems/Error Messages you are experiencing

web/components/private_route.tsx

import ServerCookie from "next-cookies";
import Router from "next/router";
import React, {Component} from "react";
import {COOKIES} from "../services/login_service";
import {AuthToken} from "../services/auth_token";

export type AuthProps = {
  auth —AuthToken
}

export function privateRoute (WrappedComponent: any) {
  return class extensions Component <AuthProps > {
    static async getInitialProps (ctx:any) {
      const token=ServerCookie(ctx) [COOKIES.authToken];
      const auth = new AuthToken(token);
      const initialProps={auth};
      if(auth.isExpired){
        ctx.res.writeHead(302,{
          Location: "/login?redirected=true",
        });
        ctx.res.end();
      }
      if(WrappedComponent.getInitialProps) returnWrappedComponent.getInitialProps(initialProps);
      return initialProps;
    }

    get auth(){
      // The server pass to the client serializes the token
      // so have to reinitialize the authToken class
      //
      // @see https://github.com/zeit/next.js/issues/3536
      return new AuthToken (this.props.auth.token);
    }

    render() {
      return<WrappedComponent auth={this.auth}{...this.props}/>
    }
  };
}


Next.js9.3 and later recommend getServerSideProps instead of getInitialProps, so
I would like to rewrite it to the following form.

import ServerCookie from "next-cookies";
import Router from "next/router";
import React, {Component} from "react";
import {COOKIES} from "../services/login_service";
import {AuthToken} from "../services/auth_token";
import {GetServerSideProps} from "next";

export type AuthProps = {
  auth —AuthToken
}

export function privateRoute (WrappedComponent: any) {
  return class extensions Component <AuthProps > {
    // static async getInitialProps (ctx:any) {
    //   const token=ServerCookie(ctx) [COOKIES.authToken];
    //   const auth = new AuthToken(token);
    //   const initialProps={auth};
    //   if(auth.isExpired){
    //     ctx.res.writeHead(302,{
    //       Location: "/login?redirected=true",
    //     });
    //     ctx.res.end();
    //   }
    //   if(WrappedComponent.getInitialProps) returnWrappedComponent.getInitialProps(initialProps);
    //   return initialProps;
    // }

    get auth(){
      // The server pass to the client serializes the token
      // so have to reinitialize the authToken class
      //
      // @see https://github.com/zeit/next.js/issues/3536
      return new AuthToken (this.props.auth.token);
    }

    render() {
      return<WrappedComponent auth={this.auth}{...this.props}/>
    }
  };
}

export cost getServerSideProps:GetServerSideProps=async(ctx:any)=>{
      const token=ServerCookie(ctx) [COOKIES.authToken];
      const auth = new AuthToken(token);
      const initialProps={auth};
      if(auth.isExpired){
        ctx.res.writeHead(302,{
          Location: "/login?redirected=true",
        });
        ctx.res.end();
      }
      if(WrappedComponent.getInitialProps) returnWrappedComponent.getInitialProps(initialProps);
      return initialProps;
}


When I actually rewritten it as above,
(1) I want to use the prop I'm returning with getServerSideProps in the privateRoute function, but I don't know how to pass it.
(2) If(WrappedComponent.getInitialProps) returnWrappedComponent.getInitialProps(initialProps); in the section "WrappedComponent" does not find the name 'WrappedComponent' and I do not know how to rewrite to getServerSideProps instead of getInitialProps.
There is a problem that has occurred and it is clogged up.
(1)As for , I thought it should be function Page({data}){ as explained in the official document, but in the case of this code, I take WrappedComponent as an argument in Component, so I don't know how to write it.
https://nextjs.org/docs/basic-features/data-fetching#simple-example-1
By the way, this Component is
web/pages/dashboard.tsx
This is a component used in and for creating pages that can only be seen when logging in, and is used in the Page code in a way similar to "export default privateRoute (Page);"

Question

(1) and (2) How can we solve this problem?
Both Next.js TypeScript are beginners, so I'm sorry if I'm misguided.I would appreciate it if you could point it out.

Tried

Read official documentation about getServerSideProps
I searched GitHub for similar codes and tried to find ways to write them for a few days, but I didn't know.

Supplementary information (for example, FW/Tool Version)

Next.js 9.5
TypeScript 3.5

javascript reactjs typescript next.js

2022-09-30 19:46

1 Answers

  • getServerSideProps cannot be used with getInitialProps.
    (Maybe it's possible, but I'm thinking about merging prop's from two sources, which makes me more hellish.)

  • getServerSideProps (and getInitialProps) are exported from the pages/ files below, so they are not handled by the following files:

  • components/The components below must receive the initial state from the pages/Page components below, either Props or per state management framework.

    • extjs-jwt-example defaults export the Component generated by privateRoute() from the pages/ file, so the pages/nantoka.tsx#default.getInitialProps file is resolved directly from the file.

getServerSideProps cannot be used with getInitialProps.
(Maybe it's possible, but I'm thinking about merging prop's from two sources, which makes me more hellish.)

getServerSideProps (and getInitialProps) are exported from pages/ files, so they are not handled by components/ files.

Components below components/ must receive the initial state from the pages/ Page components below, or per state management framework.

  • extjs-jwt-example defaults export the Component generated by privateRoute() from the pages/ file, so the pages/nantoka.tsx#default.getInitialProps file is resolved directly from the file.

Therefore, I think the reasonable design is as follows.
(Please put the file according to the project.)

export const getOrForbidenAuthToken=(ctx:GetServerSidePropsContext)=>{
  const token=ServerCookie(ctx) [COOKIES.authToken]
  const auth=new AuthToken(token)

  if(auth.isExpired){
    ctx.res.writeHead(302,{
      Location: '/login?redirected=true',
    })
    ctx.res.end()

    // Verify that there is no problem with handling exceptions roughly
    return null
  }

  return auth
}
//web/components/private_route.tsx

export function privateRoute<Pextends {auth:AuthToken}>(
  WrappedComponent—ComponentType<P>
) {
  // Receive serialized auth in getServerSideProps
  return({auth,...props}:{auth:AuthToken}&P)=>{
    // Create instances only when mounting components (google useMemo)
    const token=useMemo()=>new AuthToken(auth.token), [auth])

    // Hand over the AuthToken instance to WrappedComponent (forgive me as any)
    return<WrappedComponent auth={token}{...(props as any)}/>
  }
}
//pages/nantoka.tsx
import {getOrForbidenAuthToken} from '~yourapp/auth'

export const Page=privateRoute({auth}:{auth:AuthToken})=>{
  return<div>do something here</div>
})

export default Page

export cost getServerSideProps:GetServerSideProps=async(ctx)=>{
  // Call getOrForbidenAuthToken to return an error response, etc.
  const auth=getOrForbidenAuthToken(ctx)

  // Even if there is an error in authentication, it will be processed from then on (this line).
  /  Please guard if(auth!=null) or whatever action you need to authenticate.
  return {props:{auth}}
}

That's it.


2022-09-30 19:46

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.