Next.js: next 9.1.3 withRouter passes router=null on SSR

Created on 8 Nov 2019  路  10Comments  路  Source: vercel/next.js

Bug report

Describe the bug

withRouter passes prop router: null to wrapped component whereas in next 9.1.2 it always passed the right object (with query, etc.))

import { withRouter } from "next/router";
const Component = ({router}) => {
  console.log(router); // will be null on first render
 return <div>.....</div>
}
withRouter(Component);

To Reproduce

see component above

Expected behavior

withRouter always injects relevant data)

System information

  • OS: macOs

  • Version of Next.js: 9.1.3

Additional context

This bug was not present in 9.1.2 9.1.1. (we skipped 9.1.2)

please add a complete reproduction

Most helpful comment

A note in case anyone makes the same mistake I did:
Auto imports could pull withRouter from "next/dist/client/with-router" which will cause this issue.

To correct this make sure you import withRouter from "next/router";

All 10 comments

https://github.com/zeit/next.js/issues/9105#issuecomment-548343173 suggested that this bug was already present in 9.1.2

have to stick to 9.1.1 now

Always provide a full reproduction when creating GitHub issues. This is not enough to reproduce.

Are you using Apollo or urql by any chance?

@timneutkens yes, i am using apollo. I just started a reproduction and it does not occure on a fresh nextjs (which was to be expected). So i also thought it has to do with apollo. The apollo client is initialized in _app.jsx according to the older examples (the newer examples don't extend _app anymore, but require you to use a HOC on every page)

You'll have to use AppTree similarly to the newer examples. That's probably where it broke (the older example was doing non-standard behavior).

@timneutkens thx, this seems to work.

For other falling into the same issue:

in withApolloClient-HOC, in getMarkupFromTree, it should use <AppTree /> not <App />

it looks something like:

import { getMarkupFromTree } from "@apollo/react-ssr";
import { ApolloClient } from "apollo-boost";
import Head from "next/head";
import nookies from "nookies";
import React from "react";
import { renderToString } from "react-dom/server";
import { initApollo } from "./initApollo";


export default (App) => {
  return class Apollo extends React.Component {
    public static displayName = "withApollo(App)";

    public static async getInitialProps(appContext) {
      let appProps = {};
      const { AppTree } = appContext;
      if (App.getInitialProps) {
        appProps = await App.getInitialProps(appContext);
      }

      const { Component, router, ctx } = appContext;
      const apollo = createApollo(ctx);
      ctx.apollo = apollo;

      if (!process.browser) {
        try {
          // Run all GraphQL queries
          await getMarkupFromTree({
            renderFunction: renderToString,
            tree: (
              <AppTree {...appProps} Component={Component} router={router} apolloClient={apollo} />
            ),
          });

        } catch (error) {
          // Prevent Apollo Client GraphQL errors from crashing SSR.
          // Handle them in components via the data.error prop:
          // https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error

          // tslint:disable-next-line:no-console
          console.error("Error while running `getMarkupFromTree`", error);
        }

        // getDataFromTree / getMarkupFromTree does not call componentWillUnmount
        // head side effect therefore need to be cleared manually
        Head.rewind();
      }

      // Extract query data from the Apollo store
      const apolloState = apollo.cache.extract();
      return {
        ...appProps,
        apolloState,
      };
    }

    private apolloClient: ApolloClient<any>;

    constructor(props) {
      super(props);
      this.apolloClient = initApollo(props.apolloState);
    }

    public render() {
      return <App {...this.props} apolloClient={this.apolloClient} />;
    }
  };
};

@timneutkens sadly, i did not realize, that now SSR with apollo is broken. on SSR all components using apollo now render in loading state and apollo.cache.extract(); returns an empty object.

also https://github.com/zeit/next.js/issues/9336 seems to have a similar problem.

I now will revert to 9.1.1 and stick to that for the moment, because i think others have similar problems and there was an accidental breaking change between 9.1.1 and 9.1.3

A note in case anyone makes the same mistake I did:
Auto imports could pull withRouter from "next/dist/client/with-router" which will cause this issue.

To correct this make sure you import withRouter from "next/router";

A note in case anyone makes the same mistake I did:
Auto imports could pull withRouter from "next/dist/client/with-router" which will cause this issue.

To correct this make sure you import withRouter from "next/router";

i only include import { WithRouterProps } from "next/dist/client/with-router"; , withRouter is always imported with import { withRouter } from "next/router";

A note in case anyone makes the same mistake I did:
Auto imports could pull withRouter from "next/dist/client/with-router" which will cause this issue.

To correct this make sure you import withRouter from "next/router";

Exactly what happened to me too!

For anyone having this issue, in my case, I got this issue using useRouter's hook in a component nested inside a header section (next/head).

Moving the component outside of the head section solved the issue.

I'm using next 9.3.4.

Was this page helpful?
0 / 5 - 0 ratings