NextJS x GraphQL x Apollo Client SSR
Tags: react, graphql, nextjs, webdev
Published: 2020-04-17 07:47:58

I've built my personal blog ([https://www.ghack.dev/](https://www.ghack.dev/)) using NextJS, GraphQL with Apollo Server and Apollo Client. My blog is a Progressive and Isomorphic Web App. I experienced a tricky challenge when I want to do Server-side rendering using Apollo Client. 

## Why i need to do SSR?
I need to do SSR because I want to do SEO and I also need the data from the GraphQL query to fill page title and some meta tags in some pages in my personal blog.

I have read the documentation about Server-side rendering using Apollo Client here :
[https://www.apollographql.com/docs/react/performance/server-side-rendering/](https://www.apollographql.com/docs/react/performance/server-side-rendering/)

But I still confuse about how to implement it on my NextJS project. And then I got inspired by this library :
[https://github.com/lfades/next-with-apollo](https://github.com/lfades/next-with-apollo)

That is a very simple library that we can use to enable SSR to our NextJS x Apollo Client project. We only need to wrap our Page Component with `withApollo` HOC from the library.

The idea is to execute `getDataFromTree` method from the `@apollo/react-ssr` library and put an extracted `AppTree` component from the context as a parameter. Just like what's explained in the documentation.

Because I want a very simple implementation and I won't use HOC to execute the `getDataFromTree` method. I want to execute `getDataFromTree` inside the `getInitialProps` in my `_app` Component.

Maybe you won't include Apollo in all of your pages, in some cases, using HOC is a better approach.

Finally, I've succeed to do that and this is my code :
```javascript
import React, { useReducer, useEffect, Reducer } from 'react';
import Head from 'next/head';
import ApolloClient from 'apollo-client';
import { ApolloProvider } from '@apollo/react-hooks';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { createHttpLink } from 'apollo-link-http';
import { getDataFromTree } from '@apollo/react-ssr';
import fetch from 'isomorphic-fetch';
import AppContext, { Action, State, reducer, initialValues, appActions } from '@contexts/AppContext';
import useScroll from '@hooks/useScroll';

const link = createHttpLink({
  uri: 'https://my-graphql-server.com/graphql',
  fetch: fetch,
})

const apollo = new ApolloClient({  
  link,
  cache: new InMemoryCache()
});


const App = ({ Component, pageProps }) => {
  const [state, dispatch] = useReducer<Reducer<State, Action>>(reducer, initialValues);
  const [scroll] = useScroll();

  useEffect(() => {
    dispatch(appActions.setScrollPosition(scroll));
  }, [scroll]);

  return (
    <AppContext.Provider
      value={{
        state,
        dispatch,
      }}
    >
      <ApolloProvider
        client={apollo}
      >
        <Component {...pageProps} />
      </ApolloProvider>
    </AppContext.Provider>
  )
};

App.getInitialProps = async ({ Component, ctx }: any) => {  
  let pageProps = {} as any;
  const apolloState = {data: {}};
  const { AppTree } = ctx;

  if (Component.getInitialProps) {
    pageProps = await Component.getInitialProps(ctx);
  }

  if(typeof window === 'undefined') {
    if (ctx.res && (ctx.res.headersSent || ctx.res.finished)) {
      return pageProps;
    }

    try {
      const props = { ...pageProps, apolloState, apollo };
      const appTreeProps =
        'Component' in ctx ? props : { pageProps: props };
      await getDataFromTree(<AppTree {...appTreeProps} />);
    }catch(error) {
      console.error(
        'GraphQL error occurred [getDataFromTree]',
        error
      );
    }

    Head.rewind();

    apolloState.data = apollo.cache.extract();
  }

  return { pageProps };
}  

export default App;
```

I hope this information can be useful for you. And please, if you have a better idea to improve my code. Please leave a comment below!