adamsoffer / next-apollo

React higher-order component for integrating Apollo Client with Next.js
MIT License
482 stars 64 forks source link

How to make getInitialProps() work on Pages #24

Closed coommark closed 4 years ago

coommark commented 5 years ago

Please is it possible to make getInitialProps() to work with this library? Looks like getInitialProps() is somehow swallowed up by this HOC.

See my sample _app.js below. But getInitialProps() is never called:

class MyApp extends App {
  static async getInitialProps({ Component, router, ctx }) {
    let pageProps = {};
    console.log("IT IS WORKING")
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }
    return { pageProps };
  }

  render() {
    const { Component, pageProps, ctx } = this.props;
    return (
        <Container>
            <Component {...pageProps} />
        </Container>
    );
  }
}

export default withData(MyApp);
adamsoffer commented 5 years ago

@coommark hmm interesting. I've used _app in tandem with this library before without issue, but not while using getInitialProps. I'll try reproducing this on my end and see what the issue is.

coommark commented 5 years ago

Hi @adamsoffer, yes I use it with _app.js and it works perfect, but getInitialProps is never called on pages.

tobeycodes commented 4 years ago

@coommark I am also experiencing this. getInitialProps does not run on pages for me when using next/link. It seems to run for SSR pages

coommark commented 4 years ago

@schrapel I cannot seem to remember exactly what the issue was, but I solved this, let me share with you the relevant code: Let me know if you need more help and I can investigate later and explain. Or you can share your code here to take a look.

_app.js

import App, { Container } from 'next/app';
import { ApolloProvider } from 'react-apollo';
import withApollo from '../lib/withApollo';
import Layout from "../components/layout/Layout";

class MyApp extends App {
    static async getInitialProps({ Component, router, ctx }) {
    let pageProps = {};
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }
    return { pageProps };
  }
  render() {
    const { Component, pageProps, apollo } = this.props;
    return (
      <Container>
            <Layout>
                <ApolloProvider client={apollo}>
                  <Component {...pageProps} />
                </ApolloProvider>
            </Layout>
      </Container>
    );
  }
}

export default withApollo(MyApp)

And this is the withApollo.js

import withApollo from 'next-with-apollo';
import ApolloClient, { InMemoryCache }  from 'apollo-boost';
import { getUserFromServerCookie, getUserFromLocalCookie } from "./auth";

export default withApollo(
    ({ ctx, headers, initialState }) => {
        return new ApolloClient({
            uri: "http://localhost:8080/api/graphql",
            request: async operation => {
            const authData = process.browser
                ? getUserFromLocalCookie()
                : getUserFromServerCookie(ctx.req);
            let token = null;
            if(authData) {
                token = authData.extra.payload.token;
            }
            operation.setContext({
                headers: {
                    bearer: token ? `${token}` : ''
                }
            });
            }
        });
    },
);
tobeycodes commented 4 years ago

@coommark My code is basically as in the documentation. When you load the page directly (does a SSR) the getInitialProps runs. When you click the link and it does a client side render the getInitialProps does not run

Thank you for responding and offering your help.

I assume this happens because the code only runs it on SSR https://github.com/adamsoffer/next-apollo/blob/master/src/withData.js#L45

// /lib/apollo.ts
import { withData } from 'next-apollo'
import { HttpLink } from 'apollo-link-http'

// can also be a function that accepts a `context` object (SSR only) and returns a config
const config = {
  link: new HttpLink({
    credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
    uri: 'http://localhost:8000/graphql', // Server URL
  })
}

export default withData(config)
// /pages/get-a-quote.tsx
import React from 'react';
import withData from '../lib/apollo'

const Example = () => <div>Hello World</div>;

Example.getInitialProps = () => {
 // code here does not run
}

export default withData(Example)
// Another page
import React from 'react';
import Link from 'next/link';

const Page = () => (
  <Link href="/get-a-quote">
    <a>
      Link
    </a>
  </Link>
);

export default Page;
tobeycodes commented 4 years ago

@coommark Looks like you gave some code for a completely different repo? I guess that solved your problem 😂

https://github.com/lfades/next-with-apollo

EDIT: This package works for getInitialProps on page :)

adamsoffer commented 4 years ago

Important to note, that package uses _App.js which means apollo will run on every page, even on pages you're not using it on. This will disable the automatic static optimization next.js provides for pages that don’t need apollo which would be unfortunate.

It looks like the issue of getInitialProps() not working on pages was actually addressed in the official nexts apollo example 3 weeks ago: https://github.com/zeit/next.js/pull/8620

I'll look into doing the same for this package.

gregorskii commented 4 years ago

Hi all, is there any movement on this? :) Ran into this same issue.

EDIT: this actually works, I had a different HOC that was not passing through the getInitialProps.

gregorskii commented 4 years ago

Ok working on this more I was indeed blocking GIP from being called in my other HOC, but so is this one. Can you please check if this would work?

https://github.com/adamsoffer/next-apollo/pull/61

Seems to be working for me.

It's based on the thinking here https://github.com/zeit/next.js/pull/8620/files#diff-c7ee3d6e815d630e8d7be23ea73b6436R54

adamsoffer commented 4 years ago

Closed by #61