morrys / wora

Write Once, Render Anywhere. typescript libraries: cache-persist, apollo-offline, relay-offline, offline-first, apollo-cache, relay-store, netinfo, detect-network
https://morrys.github.io/wora/docs/introduction
MIT License
174 stars 4 forks source link

Proposal: Replace `useRestore` with `HydrationGuard` #138

Closed bglgwyng closed 1 year ago

bglgwyng commented 1 year ago

Throughout the day, I have been troubleshooting a perplexing issue with the branching logic of 'react-relay-offline', specifically with the online/offline behavior. Finally, I identified that the problem lies with the useRestore function.

Please see the following code.

const MyRelayEnvironmentProvider = () => {
  // ...

  const environment = useMemo(() => {
    // ...
    return new Environment({ network, store })
  }, [userId, token])

  const isRehydrated = useRestore(environment)
  if(isRehydrated) {
    return <Loading />
  }

  return (
    <RelayEnvironmentProvider environment={environment}>
      {props.children}
    </RelayEnvironmentProvider>
  );
}

I think this is a quite common pattern to initialize environment using useMemo to support multiple users. However, useRestore is not designed to support this pattern. useRestore uses useState internally to keep the state of hydration, so that it doesn't rehydrate the new environment when userId or token is changed. First I tried to modify useRestore to throw suspense when it's not rehydrated. But it requires an external store like 'recoil' to keep the state of rehydration. And it's not a good idea to add another dependency to react-relay-offline to solve this small problem.

So my current solution in my project looks like this.

const HydrationGuard = memo((props: PropsWithChildren) => {
  const environment = useRelayEnvironment();

  if (!environment.isRehydrated()) {
    throw environment.hydrate();
  }

  return <>{props.children}</>;
});

And this is how to use HydrationGuard

<Suspense fallback={<Loading />}>
  <MyRelayEnvironmentProvider>
    <HydrationGuard>
      <App />
    </HydrationGuard>
  </MyRelayEnvironmentProvider>
</Suspense>

I'm quite satisfied with this solution and think supporting HydrationGuard in react-relay-offline is a good idea. What do you guys think? I'm happy to make a PR if you guys think it's a good idea.

bglgwyng commented 1 year ago

I've thought of it more and just realize the very simple fact that we can just modify the implementation of useRestore also! So Please consider HydrationGuard proposal being parallel to useRestore.

morrys commented 1 year ago

moved to react-relay-offline https://github.com/morrys/react-relay-offline/issues/33#issuecomment-1649649175