DEV Community

RobbieGM
RobbieGM

Posted on

10 2

How to reload a Next.js page's initial props without reloading the whole page

If you have made a Next.js page that loads data in its getInitialProps function, you may have wanted to reload it in order to fetch the newest data after making some mutating API call. Hard-reloading the page will reset the user's scroll position and take extra time, so clearly that is not the best solution. You could also make some fetchData function that gets called in getInitialProps, passes its data into the default value of a useState hook, and then gets updated by calling fetchData again followed by setting the state. But wouldn't it be convenient if you could just have a function that reloaded your initial props?
I made a higher order component to wrap Next.js pages that does exactly this. Here it is in TypeScript:

import { NextPage, NextPageContext } from 'next';
import React, { useState, PropsWithChildren, ComponentType } from 'react';

export interface SoftReloadProps {
  /**
   * Reloads the page's initialProps without causing a real browser "hard" reload.
   */
  softReload(): void;
}

type OmitSoftReloadProps<T> = Omit<T, keyof SoftReloadProps>;
type SoftReloadablePageInitialProps<TProps> = OmitSoftReloadProps<TProps> & { context: NextPageContext };
export type NextPageWithInitialProps<P, IP = P> = NextPage<P, IP> & Required<Pick<NextPage<P, IP>, 'getInitialProps'>>;

/**
 * Removes never-used context values to reduce bloat. Context values may come from server but then
 * be used client-side because they are saved in initial props.
 */
function minifyContext(context: NextPageContext): NextPageContext {
  return { ...context, req: undefined, res: undefined };
}

const withSoftReload = <TProps extends SoftReloadProps>(
  Page: NextPageWithInitialProps<TProps, OmitSoftReloadProps<TProps>>
): NextPage<SoftReloadablePageInitialProps<TProps>> => {
  async function getInitialProps(ctx: NextPageContext): Promise<SoftReloadablePageInitialProps<TProps>> {
    return { context: minifyContext(ctx), ...(await Page.getInitialProps(ctx)) };
  }
  const omitContextFromProps = ({
    context,
    ...props
  }: SoftReloadablePageInitialProps<TProps>): OmitSoftReloadProps<TProps> => props as any;
  const NewPage: NextPageWithInitialProps<SoftReloadablePageInitialProps<TProps>> = props => {
    // set inner page initial props to wrapper initial props minus context
    const [initialProps, setInitialProps] = useState(omitContextFromProps(props));
    async function softReload() {
      setInitialProps({ children: null, ...(await Page.getInitialProps(props.context)) });
    }
    return (
      <Page
        {...(({ ...initialProps, softReload } as Omit<TProps, keyof SoftReloadProps> & SoftReloadProps) as TProps)}
      />
    );
  };
  NewPage.getInitialProps = getInitialProps;
  NewPage.displayName = `withSoftReload(${Page.displayName})`;
  return NewPage;
};

export default withSoftReload;

You can use this HOC like this in your pages:

interface InitialProps {
  data: string;
}

const MyPage: NextPageWithInitialProps<InitialProps & SoftReloadProps, InitialProps> = ({ data, softReload }) => (
  <div>
    {data}
    <button onClick={softReload}>Refresh</button>
  </div>
);

MyPage.getInitialProps = async (ctx) => {
  // fetch data
};

export default withSoftReload(MyPage);

Hope you enjoy!

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (3)

Collapse
 
w3bdesign profile image
w3bdesign

From the NextJS documentation:

If you're using Next.js 9.3 or newer, we recommend that you use getStaticProps or getServerSideProps instead of getInitialProps.

These new data fetching methods allow you to have a granular choice between static generation and server-side rendering.

Collapse
 
robbiegm profile image
RobbieGM

I've considered using getServerSideProps but then it wouldn't work client side. I use isomorphic fetching in getInitialProps, what is the new recommended way to do that?

Collapse
 
bayuangora profile image
Bayu Angora

How to implement this on Hugo?

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →