jotaijs / jotai-urql

Jotai integration library for URQL
MIT License
29 stars 5 forks source link

Can not disable suspense behaviour #13

Closed barthuijgen closed 1 year ago

barthuijgen commented 1 year ago

I'm trying to use jotai-urql to execute subscriptions, with my graphql atom as following

export const accountIdAtom = atom<string | null>(null);
export const playerAtom = atomWithSubscription({
  query: query,
  getVariables: (get) => ({ id: get(accountIdAtom) }),
  getPause: (get) => !get(accountIdAtom),
  getClient: () => client,
  getContext: () => ({ suspense: false }),
});

I've been trying to disable the suspense behaviour, and found getContext: () => ({ suspense: false }) in the typescript autocomplete, but it does not seem to do anything. And I can not find any other documentation to disable it.

RIP21 commented 1 year ago

Yeah, it won't disable that.

Docs are still yet to be updated, apologies for that :)

The trick is following.

Add useHydrateAtoms to the root of your app. And override suspenseAtom to be false. This will disable suspense for jotai-urql

import { useHydrateAtoms } from 'jotai/react/utils'
import { atomWithQuery, suspenseAtom } from 'jotai-urql'

export const App = () => { 
  useHydrateAtoms([[suspenseAtom, false]])
  ...
}
RIP21 commented 1 year ago

You can do it at the same time when you sync the client to be the same for urql original react bindings and jotai-urql. Obviously, if you use both :)

Let me know if it will work out. But it should as we have tests for it :)

RIP21 commented 1 year ago

suspense: false really does nothing at all. So setting it to true or false will not affect anything as it's used only by original react URQL client bindings.

barthuijgen commented 1 year ago

I did find the global suspenseAtom after digging through the source code, thanks for te quick reply!

I think this will cover my use case for now, but I am curious if you are looking to support changeing this on a query level instead of globally. I think in my project I will use many different subscriptions, for some I know suspense is not an option, for others it might be usefull.

Also is using useHydrateAtoms really needed when I already pass the same urql instance to both getClient and the urql provider?

I solved it currently by using jotaiStore.set(suspenseAtom, false); but I saw if no provider is used then getDefaultStore().set(suspenseAtom, false); will work as well.

barthuijgen commented 1 year ago

Ah I see if you provide the client in useHydrateAtoms you don't need to pass it in the query at all. That is usefull. I've updated my providers like this now.

import { Provider as UrqlProvider } from "urql";
import { Provider as JotaiProvider } from "jotai/react";
import { suspenseAtom, clientAtom } from "jotai-urql";
import { useHydrateAtoms } from "jotai/react/utils";
import { jotaiStore } from "./services/jotai";
import { urqlClient } from "./services/graphql";

const HydrateAtoms = ({ children }: React.PropsWithChildren) => {
  useHydrateAtoms([
    [clientAtom, urqlClient],
    [suspenseAtom, false],
  ]);
  return <>{children}</>;
};

export function Providers({ children }: React.PropsWithChildren) {
  return (
    <UrqlProvider value={urqlClient}>
      <JotaiProvider store={jotaiStore}>
        <HydrateAtoms>{children}</HydrateAtoms>
      </JotaiProvider>
    </UrqlProvider>
  );
}
RIP21 commented 1 year ago

Yes. Everything is correct :)

It seems you're more aware of Jotai tips and tricks than I do :D (have maybe 100 hours with Jotai, not more than that)

I've rewritten these bindings last week, so it's in its early, days but I tested it A LOT. Spent 50-60 hours of pure coding (which I tracked using Wakatime) and testing on it :)

I think you should be able to partially disable suspense for part of the tree, using nested Providers that allow for atoms isolation. But I'm not super familiar with this approach, so I won't give you a recipe, but something along those lines should be definitely possible. Just in one part of the tree, you'll have suspenseAtom: true and in another false.

RIP21 commented 1 year ago

Also is using useHydrateAtoms really needed when I already pass the same urql instance to both getClient and the urql provider?

Yeah, it will just use a global clientAtom :)

The only thing that is required is query and, sometimes getVariables in case your query has variables that have to be fulfilled. TS types should handle that. It also supports TypedDocumentNode and, obviously, generics.