Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use getServerSideProps for every pages in next.js?

I have set a cookie with nookies which store the values of all the products selected by user. I want to fetch the cookie in server side using getServerSideProps and pass the value as props. I have to display the value of cookie on all pages.

When I tried getServerSideProps in _app.js. It did not worked and it did not even run the code.

Is there any way to do it?

like image 575
angelo Avatar asked Jan 11 '21 14:01

angelo


People also ask

Can I use getServerSideProps in _app js?

As long as you don't implement getInitialProps, getStaticProps, getServerProps in _app.

Where can I use getServerSideProps?

If you want to render a page at the time of the request, you can use getServerSideProps to render a page on the server before responding to a request. getServerSideProps will mark the page to be rendered on each request.

What is getServerSideProps in NextJS?

getServerSideProps or API RoutesAn API route is used to fetch some data from a CMS. That API route is then called directly from getServerSideProps . This produces an additional call, reducing performance. Instead, directly import the logic used inside your API Route into getServerSideProps .

What is difference between getStaticProps and getServerSideProps?

getStaticProps(): A method that tells the Next component to populate props and render into a static HTML page at build time. getServerSideProps(): A method that tells the Next component to populate the props and render into a static HTML page at run time.

What is getserversideprops and how to use it?

In simple terms, getServerSideProps enables a page to render server-side. getServerSideProps renders your client-side page in server-side and returns a hydrated SEO-friendly HTML document to the browser. Meaning getServerSideProps pre-renders the page on each request using the data it retrieves from the server. Table of content 1.

How do I export getserversideprops?

The only way to export getServerSideProps is from a page. It is not possible to ship it from non-page files. It is important to note that getServerSideProps must be exported as a standalone function; it won't work if we make it a page component property. When should we use getServerSideProps?

How does next JS pre-rendering work?

By default, Next.js pre-renders every page. This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. Pre-rendering can result in better performance and SEO. Each generated HTML is associated with minimal JavaScript code necessary for that page.

Can I write server-side code in getserversideprops?

Imports used will not be bundled for the client-side. This means you can write server-side code directly in getServerSideProps, including fetching data from your database. The context parameter is an object containing the following keys:


3 Answers

getServerSideProps does not work in _app.js. see docs.

you could use the older getInitialProps in your custom app component but then the automatic static optimisation is disabled, which is something Next.js bets on heavily.

it might be worth digging into your cookie use case and figure out if you really need to read it on the server side.

like image 153
dmudro Avatar answered Oct 24 '22 10:10

dmudro


As of now, there isn't a built-in way to do it, so I've resorted to doing the following.

First, I created a file that holds the getServerSideProps function I want to run on every page:

// lib/serverProps.js
export default async function getServerSideProps(ctx) {
  // do something
  return {
    // data
  };
}

Then in every page (yes, every, I can't find a workaround; it might even be helpful if you don't need the code to execute on server pages), do:

import getServerSideProps from "../lib/serverProps";

// other stuff...

export { getServerSideProps };

or

// other stuff...

export { default as getServerSideProps } from "../lib/serverProps";

If you want to add other code to run inside getServerSideProps for a specific page, you could do something along the lines...

import serverProps from "../lib/serverProps";

// other stuff...

export async function getServerSideProps(ctx) {
  // do custom page stuff...
  return {
    ...await serverProps(ctx),
    ...{
      // pretend this is what you put inside
      // the return block regularly, e.g.
      props: { junk: 347 }
    }
  };
}
like image 14
code Avatar answered Oct 24 '22 08:10

code


For those wanting to share state received from a page's getServerSideProps function to global components in pages/_app.tsx, I've pieced this solution together.

  • Create a shared getServerSideProps function to include on all pages
  • Create a shared useSetUserStorage custom hook to include on all pages
  • Listen for localStorage changes with custom event listener in global component (e.g. GlobalNav)

It's a work around, but is working for me so far (note that it includes some specifics to my use of getServerSideProps function).

It's a fair amount of code but hopefully this helps someone:

// src/pages/_app.tsx

import type { AppProps } from "next/app";

import GlobalNav from "../components/GlobalNav";

function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
  return (
    <>
      <GlobalNav /> // <— your global component
      <Component {...pageProps} />
    </>
  );
}

export default MyApp;
// src/utils/getServerSideProps.ts

import { ppinit, ppsession, sess } from "../authMiddleware";
import nc from "next-connect";
import { NextApiRequest, NextApiResponse } from "next";

import { User } from "../types/types";

interface ExtendedReq extends NextApiRequest {
  user: User;
}

interface ServerProps {
  req: ExtendedReq;
  res: NextApiResponse;
}

interface ServerPropsReturn {
  user?: User;
}

//
// Here we use middleware to augment the `req` with the user from passport.js
// to pass to the page
// src: https://github.com/hoangvvo/next-connect/tree/21c9c73fe3746e66033fd51e2aa01d479e267ad6#runreq-res
//
const getServerSideProps = async ({ req, res }: ServerProps) => {
  // ADD YOUR CUSTOM `getServerSideProps` code here
  const middleware = nc()
    .use(sess, ppinit, ppsession)
    .get((req: Express.Request, res: NextApiResponse, next) => {
      next();
    });

  try {
    await middleware.run(req, res);
  } catch (e) {
    // handle the error
  }

  const props: ServerPropsReturn = {};
  if (req.user) props.user = req.user;
  return { props };
};

export interface Props {
  user?: User;
}

export default getServerSideProps;
// src/hooks.ts

import { useEffect } from "react";

import { User } from "./types/types";

export const useSetUserStorage = (user?: User) => {
  useEffect(() => {
    if (user) {
      localStorage.setItem("user", JSON.stringify(user));
    } else {
      localStorage.removeItem("user");
    }

    // whether setting or removing the user, dispatch event so that `GlobalNav`
    // component (which is above the page implementing this hook in the
    // component hierarchy) can be updated to display the user status.  we
    // can't use `window.addEventListener('storage', handler)` as this only
    // works for listening for events from other pages
    document.dispatchEvent(new Event("localStorageUserUpdated"));
  });

  return null;
};
// src/pages/index.tsx (or any page)

import { useSetUserStorage } from "../hooks";

import { Props } from "../utils/getServerSideProps";
export { default as getServerSideProps } from "../utils/getServerSideProps";

export default function Home({ user }: Props) {
  useSetUserStorage(user);

  return (
    <>
      <h1>Welcome to my app {user?.username}</h1>
    </>
  );
}
// src/components/GlobalNav.ts (or another global component)

import { useEffect, useState, MouseEvent } from "react";

import { User } from "../types/types";

const GlobalNav = () => {
  const [user, setUser] = useState<User | null>(null);

  useEffect(() => {
    const handleUserLocalStorage = () => {
      const userString = localStorage.getItem("user");

      try {
        if (userString) {
          setUser(JSON.parse(userString));
        } else {
          setUser(null);
        }
      } catch (e) {
        // handle parse error
      }
    };

    handleUserLocalStorage();
    // this component (`GlobalNav`) lives at the application level, above the
    // pages, but the pages receive the user object from `getServerSideProps`,
    // so this listener listens for when a page tells us the user object has
    // changed so we can update the `user` state here.
    document.addEventListener(
      "localStorageUserUpdated",
      handleUserLocalStorage,
      false,
    );

    return () => {
      // remove listener if component unmounts
      document.removeEventListener(
        "localStorageUserUpdated",
        handleUserLocalStorage,
      );
    };
  }, []);

  return (
    <div>
      {user?.username}
    </div>
  );
};
export default GlobalNav;
like image 2
fredrivett Avatar answered Oct 24 '22 10:10

fredrivett