RevereCRE/relay-nextjs

approach recommended by vercel

jantimon opened this issue · 4 comments

next js shows an approach which allows using relay with:

  • ssr data loading
  • static build time loading
  • client side only data loading

the initEnvironment uses the native nextjs way to transfer data without adding another script tag: https://github.com/vercel/next.js/blob/canary/examples/with-relay-modern/lib/relay.js

it seems to be easier for integration as it doesn't require a _document.tsx

do you see any disadvantage in their approach?

The disadvantage is similar to other libraries I’ve seen in that they all rely on getServerSideProps or something similar. From my experience building apps, it is very much an anti pattern when using Relay. One of the largest benefits of Relay is that you can render using partially cached data and then re-fetch in the background, all while not delaying the navigation like getServerSideProps does. I understand it’s recommended by Vercel over getInitialProps, however it’s a far worse user experience when we have Relay at our disposal.

We could technically remove the need for the _document addition I think by using the inline useMemo like they do, although that seems like a hack destined to break in a future version of React.

Thanks for your fast feedback 👍

I tried to draw the flow you described:

Excalidraw

So if I understand you correctly both cases behave the same way for a warm cache.

For an empty cache your approach might have an advantage depending on how fast the hydration is.
Your approach would be able to show other cached fragments or at least skeletons in the meantime instead of a blank white page. Right?

Just a minor side note on useMemo:

useMemo can easily be replaced by a concurrency save useState call in this case:

// creates an instance once and store it until component dies
const [example] = useState(() => new Example());

For an empty cache your approach might have an advantage depending on how fast the hydration is.

You're mixing SSR + hydration + relay cache in your comparison which doesn't make sense I think. It's either SSR + hydration or if it's a local navigation instead of the initial page load there won't be SSR nor hydration. I'll make a comparison best to my knowledge:

Initial page load:

Probably the same except that the next.js example is way more simple and uses next.js features to move the data instead of creating a scirpt tag to the document. Obviously the example works with static pages while relay-nextjs doesn't.

Page navigation:

Next.js way getStaticProps

I personally don't have any interest towards static pages so I'm not going to think about this too much. I'll just note that I don't think the example works with with relay cache properly, navigating to a new page will nuke the old cache with a new one.

Next.js way getServerSideProps

I had to make some assumptions here that it means getServerSideProps, since as far as I can see, the example does not have ssr data loading not client side only loading. It only has a static page.

  • Will not use relay cache at all on page navigations, because getServerSideProps is fired on page navigation, it has no way of knowing that the data is already in cache. Nothing will be rendered while the app waits for getServerSideProps even if all of the required data would already be available.
  • Will cause latency on navigation since clicking link doesn't do anything until getServerSideProps returns the data. Will confuse users since initially it can seem like the links don't work
  • Will make it not possible to render skeletons on page navigations

Next.js way client side only

In my opinion this is the best option if we don't count relay-nextjs, but it does have a major drawback:

  • Doesn't have SSR

relay-nextjs (getInitialProps)

  • Doesn't have any of the above issues apart from not working with getStaticProps

It's possible that I got some details work, since the example doesn't seem to work. The api is broken and I'm too lazy to setup the api locally.

@FINDarkside Accurate and excellent summary! Thanks!