How to fetch data in HOC from server in Next.js?

I created new app with Next.js 9.3.1.

In old app with SSR, I can use getInitialProps function in HOC components (not in the page), so I can fetch data from server in the HOC component and from page. Like this https://gist.github.com/whoisryosuke/d034d3eaa0556e86349fb2634788a7a1

Example:

export default function withLayout(ComposedComponent) {
  return class WithLayout extends Component {
    static async getInitialProps(ctx) {
      console.log("ctxlayout fire");
      const { reduxStore, req } = ctx || {};
      const isServer = !!req;
      reduxStore.dispatch(actions.serverRenderClock(isServer));

      if (isServer)
        await reduxStore.dispatch(navigationActions.getListMenuAction("menu"));
      // Check if Page has a `getInitialProps`; if so, call it.
      const pageProps =
        ComposedComponent.getInitialProps &&
        (await ComposedComponent.getInitialProps(ctx));
      // Return props.
      return { ...pageProps };
    }

    render() {
      return (
        <div className="app__container">
          <Header />
          <Navbar />
          <ComposedComponent {...this.props} />
        </div>
      );
    }
  };
}

But in new version of Next.js with SSG, I can't find the way to use getStaticProps or getServerSideProps in HOC components. If I use getInitialProps in HOC (layout), I won't be able to use getStaticProps or getServerSideProps in child.

So, how can I use getStaticProps or getServerSideProps to fetch data and pre-render in both HOC component and page?

Upvotes: 17

Views: 4120

Answers (1)

juliomalves
juliomalves

Reputation: 50278

Because getServerSideProps/getStaticProps need to be directly exported from the page component's file you have to extract that logic into a separate higher-order function (HOF) entirely.

You can keep the React component part as is in the withLayout HOC.

// hoc/with-layout.js
export default function withLayout(ComposedComponent) {
    return class WithLayout extends Component {
        render() {
            return (
                <div className="app__container">
                    <Header />
                    <Navbar />
                    <ComposedComponent {...this.props} />
                </div>
            );
        }
    };
}

The code that was inside getInitialProps will be moved to a separate HOF. This HOF will accept a getServerSideProps function as a param, and return another function where the logic will be.

// hoc/with-layout.js
export function withLayoutGSSP(gssp) {
    return async (context) => {
        //Add higher-order function logic here
        
        // Return by calling the passed `getServerSideProps` function
        return await gssp(context);
    };
}

This can then be used as follows in a page component that exports a getServerSideProps function (the same would be done for any page component where you'd want to reuse the HOC).

import withLayout, { withLayoutGSSP } from '<path-to>/hoc/with-layout'

const IndexPage = () => {
    // Your page component code
};

export const getServerSideProps = withLayoutGSSP(context => {
    // Your `getServerSideProps` code here
});

export default withLayout(IndexPage);

The same approach could be used for getStaticProps.

Upvotes: 3

Related Questions