Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atoms always triggering suspense #1007

Closed
justinhandley opened this issue Feb 10, 2022 · 13 comments
Closed

Atoms always triggering suspense #1007

justinhandley opened this issue Feb 10, 2022 · 13 comments

Comments

@justinhandley
Copy link
Contributor

I have an app that is not using any async atoms, however, suspense is required and is triggering in weird places.

Why would this be?

These are the atoms defined.

export const tokenAtom = atomWithStorage('token', null, storage)
export const skipIntroAtom = atomWithStorage('skipIntro', false, storage)
export const userAtom: WritableAtom<Promise<User>, unknown, Promise<void>> = atomWithStorage('user', null, storage)
export const plusAtom = atomWithToggleAndStorage('plus', false, storage)
export const isAuthenticatedAtom = atom<boolean>((get) => !!get(tokenAtom))
export const isAdminAtom = atom<boolean>((get) => get(userAtom)?.role === Role.Admin)

I can't use the app without suspense, and whenever I try to use the userAtom it trigger suspense, even though that is populated once and stays static throughout.

@dai-shi
Copy link
Member

dai-shi commented Feb 10, 2022

Hi, looks like you have a promise somewhere in atoms, right?
I think you'd want to eliminate promises in atom values completely if you want to avoid suspense.

If you could create a minimal reproduction in codesandbox, we might be able to see how it's going more closely.

@justinhandley
Copy link
Contributor Author

So, when you say a promise somewhere in the atoms, I don't think so. All of these literally replaced calls to useState and are just set and retrieved. I am using the helper

export function atomWithToggleAndStorage(
  key: string,
  initialValue?: boolean,
  storage?: any,
): WritableAtom<boolean, boolean | undefined> {
  const anAtom = atomWithStorage(key, initialValue, storage)
  const derivedAtom = atom(
    (get) => get(anAtom),
    (get, set, nextValue?: boolean) => {
      const update = nextValue ?? !get(anAtom)
      set(anAtom, update)
    },
  )

  return derivedAtom
}```

Would that count as async even though it doesn't declare async?

A minimum viable is hard here as this is the auth system for a react native app so I'm not sure how to get an easy minim reproduction.

@justinhandley
Copy link
Contributor Author

So, actually, I'm assuming this is because I'm using AtomwithStorage and that uses AsyncStorage on React Native. I can try to look at the source, I guess the question is, for these, is there any way to let the AsyncStorage happen in the background, so that it would literally only call the value from storage the very first time, when it doesn't have a value, and then it would maintain a non-async state, just writing / updating the AsyncStorage in the background without causing us to have to await a value that should be in local state?

@dai-shi
Copy link
Member

dai-shi commented Feb 10, 2022

ah, gotcha. yeah, atomWithStorage with async storage will suspend.
We have delayInit option (not yet documented 👉 #805), which covers your use case.

  const anAtom = atomWithStorage(key, initialValue, { ...storage, delayInit: true })

related: #780

@crucialfelix
Copy link

atomWithQuery also triggers it even without actually calling a fetch or returning a Promise or using async.

Possibly this is because the writeable part defaults to return type Promise. I don't yet understand what triggers it.

React 18 is RC and they may release it very soon. I will probably choose to use the RC shortly so I can start using Suspense.

Wonderful library! Thank you for Jotai!

@dai-shi
Copy link
Member

dai-shi commented Feb 16, 2022

@crucialfelix
For atomWithQuery in jotai/query, if you specify initialData, it will not suspend.
Also, you don't need React 18 to use Suspense feature.

@urielvan
Copy link

urielvan commented Mar 3, 2022

@crucialfelix For atomWithQuery in jotai/query, if you specify initialData, it will not suspend. Also, you don't need React 18 to use Suspense feature.

but calling refetch still needs Suspense, right?
demo

@dai-shi
Copy link
Member

dai-shi commented Mar 3, 2022

but calling refetch still needs Suspense, right?

Oh, yeah. You are right. So, the only solution would be loadable util.

@dai-shi
Copy link
Member

dai-shi commented Mar 4, 2022

Closing as answered. Please open a new discussion for further discussion.

@dai-shi dai-shi closed this as completed Mar 4, 2022
@ortonomy
Copy link

Oh, yeah. You are right. So, the only solution would be loadable util.

What is the loadable util?

@dai-shi
Copy link
Member

dai-shi commented Nov 30, 2022

What is the loadable util?

https://github.com/pmndrs/jotai/blob/25dff8d2122f44f3717b57c2a1085a0efbbb4970/docs/utils/loadable.mdx

@ortonomy
Copy link

Thank you @dai-shi - I feel like this should be more prominent on the tanstack/react-query page https://jotai.org/docs/integrations/query - it's so relevant here. We've been desperately trying to track down why our react app is suspending after loading... it's impossible to find out what is causing a suspend and finally tracked it to jotai...

@dai-shi
Copy link
Member

dai-shi commented Nov 30, 2022

I missed the context. If it's about tanstack/query, you can use the second atom to avoid suspense.

https://jotai.org/docs/integrations/query

The return values have two atoms. The first one is called dataAtom and it's an atom for the data from the observer. dataAtom requires Suspense. The second one is called statusAtom and it's an atom for the full result from the observer. statusAtom doesn't require Suspnse.

If you have suggestions to improve the wording, would you please open a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants