Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Next.js - understanding getInitialProps

I have an app that uses next.js along with Apollo/ Graphql and i'm trying to fully understand how the getInitialProps lifecycle hook works.

The lifecycle getInitialProps in my understanding is used to set some initial props that will render server side for when the app first loads which can be used prefetch data from a database in order to help SEO or simply to enhance page load time.

My question is this:

Every time I have a query component that fetches some data in my components across my app, do I have to use getInitialProps to be sure that data will be rendered server side?

My understanding is also that getInitialProps will only work in the page index components (as well as in _app.js), this would mean that any component lower down in the component tree would not have access to this lifecycle and would need to get some initial props from way up at the page level and then have them passed down the component tree. (would be great if someone could confirm this assumption)

Here is my code:

_app.js (in /pages folder)

import App, { Container } from 'next/app';
import { ApolloProvider } from 'react-apollo';

class AppComponent extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {};
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }
    // this exposes the query to the user
    pageProps.query = ctx.query;
    return { pageProps };
  }
  render() {
    const { Component, apollo, pageProps } = this.props;

    return (
      <Container>
        <ApolloProvider client={apollo}> 
          <Component client={client} {...pageProps} />               
        </ApolloProvider>
      </Container>
    );
  }
}

export default AppComponent;

Index.js (in /pages/users folder)

import React, { PureComponent } from 'react';
import { Query } from 'react-apollo';
import gql from 'graphql-tag';

const USERS_QUERY = gql`
  query USERS_QUERY {
    users {
      id
      firstName
    } 
  }
`;

class Index extends PureComponent {
  render() {
    return (
      <Query query={USERS_QUERY}>
        {({data}) => {
          return data.map(user => <div>{user.firstName}</div>);
        }}
      </Query>
    );
  }
}

export default Index;
like image 660
red house 87 Avatar asked May 16 '19 21:05

red house 87


1 Answers

The answer is NO

If you use Apollo with Next JS you will not have to use getInitialProps on each page to get some initial data rendered server side. The following configuration for getInitialProps is enough for all the components to render out with their respective queries if they have <Query> components in them

static async getInitialProps({ Component, ctx }) {
    let pageProps = {};
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }
    // this exposes the query to the user
    pageProps.query = ctx.query;
    return { pageProps };
  }

My issue and why I wasnt seeing any server side rendering is that Heroku or Now wouldnt perform SSR with a public URL ie my-app.heroku.com. To resolve this I purchased and applied a custom URL in Heroku and it worked. Along with a custom URL I had the following configuration in my Apollo config

  const request = (operation) => {
    operation.setContext({
      fetchOptions: {
        credentials: 'include'
      },
      headers: { cookie: headers.cookie }
    });
  }; 

This completely resolved it and now I have SSR without the pain of having to manually set getInitialProps on each page

Hope this helps someone

like image 137
red house 87 Avatar answered Oct 07 '22 05:10

red house 87