reactql / kit

ReactQL starter kit (use the CLI)
https://reactql.org
229 stars 38 forks source link

Apollo not SSRing properly with Async Graphql queries. #87

Closed NiluK closed 6 years ago

NiluK commented 6 years ago

Hi @leebenson,

I'm not entirely sure if this is a ReactQL issue or a Apollo issue but it looks like ReactQL does not server side render properly if an asynchronous request is used in the resolver.

I have a query that does this:

import axios from 'axios';
import { heroArticleType } from 'src/graphql/types';

export default {
  name: 'heroArticle',
  description: 'Get a the  for SITE_NAME',
  type: heroArticleType,
  async resolve(category) {
    let hero;
    let errors;
    try {
      const articles = await axios.get('API_URL_HERE');
      hero = articles.data._embedded.article.filter(article => article.featuredType === 'HERO')[0];
    } catch (e) {
      errors = e;
    }
    return hero || errors;
  },
};

And the resulting screenshot when in a JavaScript enabled environment renders correctly:

Resulting Render

However, in the server it does not seem to render at all.

View Source

I expect to see "Fnatic and 1907 Fenerbache..." somewhere along there. Alas there is none. Debugging shows me that Apollo sticks in the loading state during the server.

Is there a way to force the Koa server to wait til Apollo has done fetching the data so that the server side render is properly implemented?.

Thank you very much.

leebenson commented 6 years ago

@NiluK - can you also include the code of the React component that uses this data, please?

It should definitely be waiting:

screen shot 2017-09-27 at 13 15 38
NiluK commented 6 years ago

@leebenson Sure, here you go

import React, { Component } from 'react';

import { Link } from 'react-router-dom';
import { graphql } from 'react-apollo';
import heroArticleQuery from './heroQuery.gql';
import moment from 'moment';
import s from './styles.scss';

@graphql(heroArticleQuery, {
  options: props => ({
    variables: {
      slug: props.match.params.person,
    },
  }),
})
class Hero extends Component {
  render() {
    const { loading, heroArticle } = this.props.data;
    const { title, previewImage, snippet, firstApprovedAt, user } = heroArticle || {};
    return (
      <div
        className={`${s.hero} row`}
        style={{
          background: `linear-gradient(rgba(0, 0, 0, 0),rgba(0, 0, 0, 0.95)),rgba(0, 0, 0, 0.55) url('${previewImage}') no-repeat center right`,
        }}>
        <Link to="/">
          <div className={s.heroOverlayLink} />
        </Link>
        <div className={s.heroContent}>
          <Link to="/">
            <h1 className={s.heroArticleTitle}>{title}</h1>
          </Link>
          <div className="hidden-md-down">
            <p className={s.heroArticleSubtitle}>{snippet}</p>
          </div>
          <p className={s.heroArticleSubtitle}>
            <span className={s.heroArticleSubtitleTime}>
              &nbsp; - &nbsp;
              {moment(firstApprovedAt).fromNow()}
            </span>
          </p>
        </div>
      </div>
    );
  }
}

export default Hero;

here is the query file as well

query {
  heroArticle {
    url,
    snippet,
    previewImage
    title,
  }
}
NiluK commented 6 years ago

@leebenson I managed to figure out the issue, it was unrelated to the kit.

The components were encapsulated in a ScrollToTop container:

import { withRouter } from 'react-router-dom';
import { Component } from 'react';

class ScrollToTop extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location && !SERVER) {
      window.scrollTo(0, 0);
    }
  }

  render() {
    return this.props.children;
  }
}

export default withRouter(ScrollToTop);

And the routing was done like this:

<ScrollToTop>
      <Helmet
        title="ReactQL application"
        meta={[
          {
            name: 'description',
            content: 'ReactQL starter kit app',
          },
        ]} />
      <Switch>
        {routes.map(({ path, component, exact }) => (
          <Route path={path} exact={exact} component={component} />
        ))}
        <Route path="*" component={NotFound} />
      </Switch>
  </ScrollToTop>

Looks like SSR was failing because there was no div tag encapsulating the Helmet and Switch tags, once I added that, it SSRed properly once again.

Thanks.

NiluK commented 6 years ago

__