Relay: LocalQueryRenderer uses useLayoutEffect which warns during server-rendering

Created on 16 Sep 2019  路  4Comments  路  Source: facebook/relay

I'm using Next.js with Relay. We used fetchQuery to run a query in getInitialProps, which populates the store.

Until now we've used relay-query-lookup-renderer with STORE_ONLY during render to make sure all the subscriptions are set up correctly, but this breaks with 6.0. I tried switching to LocalQueryRenderer, which works, but warns on the server during render due to its use of useLayoutEffect.

enhancement wontfix

Most helpful comment

Further that, I have found where the memory leak is occurring. In fact, it isn't a memory leak per-se. Just an ever growing Map that never gets cleared.

https://github.com/facebook/relay/blob/02d9e7113774ef4852f90b91308adab09e8729fa/packages/relay-experimental/FragmentResource.js#L440-L451

that block, is responsible for it.

  • dataResources is created as a map once.
  • With SSR, we create a new Relay Environment for every SSR request. (Speaking of which, now that I think about it - really we should _only_ be re-creating a new Store on every request?)

Few solutions I've come up with is:

  1. Change it to a WeakMap, so if the environment gets gc'd the map would loose reference.
- const dataResources: Map<IEnvironment, FragmentResource> = new Map();
+ const dataResources: Map<IEnvironment, FragmentResource> = new WeakMap(); 
  1. Retain Environment, but on every request, simply:
// init
let store = new Store(...);

new Environment({
    network,
    get store() {
        return store;
    },
});

// new request
store = new Store(...);

All 4 comments

@AndrewIngram do you have any examples (or tips, etc) of how you're getting Next SSR + Relay to work together, by chance? We've been unable to upgrade to v5 (let alone v6) due to SSR memory leaks from Relay, and it sounds like you have a similar setup to us.

@merrywhether this is gold. We are experiencing the same memory leaks issues you are. However, I have it down to using relay-experimental/useFragment.

"babel-plugin-relay": "7.1.0",
"react-relay": "0.0.0-experimental-a1a40b68",
"relay-compiler": "7.1.0",
"relay-config": "7.1.0",
"relay-runtime": "7.1.0",

That exact same version spec, when using hooks: memory leaks. The exact same code using createFragmentContainer doesnt memory leak. So there is something leaking with the SSR. Mind you, we are _only_ using useFragment, everything else is still _current_ stuff.

Further this, I will spin up a repro-repo, and steps to track heap. But basically node server --expose-gc --inspect then just Chrome DevTools that port, snapshot, flood the gates, snap again. In my case, went from 14MB to 90MB, after a 15min pause, GC still hasnt cleaned up (with no load).

image

cc @sibelius

Further that, I have found where the memory leak is occurring. In fact, it isn't a memory leak per-se. Just an ever growing Map that never gets cleared.

https://github.com/facebook/relay/blob/02d9e7113774ef4852f90b91308adab09e8729fa/packages/relay-experimental/FragmentResource.js#L440-L451

that block, is responsible for it.

  • dataResources is created as a map once.
  • With SSR, we create a new Relay Environment for every SSR request. (Speaking of which, now that I think about it - really we should _only_ be re-creating a new Store on every request?)

Few solutions I've come up with is:

  1. Change it to a WeakMap, so if the environment gets gc'd the map would loose reference.
- const dataResources: Map<IEnvironment, FragmentResource> = new Map();
+ const dataResources: Map<IEnvironment, FragmentResource> = new WeakMap(); 
  1. Retain Environment, but on every request, simply:
// init
let store = new Store(...);

new Environment({
    network,
    get store() {
        return store;
    },
});

// new request
store = new Store(...);

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings