jotaijs / jotai-tanstack-query

Jotai integration library for TanStack Query
MIT License
210 stars 14 forks source link

`atomsWithQueryAsync` infinite loop #53

Open purecopy opened 10 months ago

purecopy commented 10 months ago

I discovered that there is an infinite loop, when the queryFn from atomsWithQueryAsync throws an error and I am subscribed to the status-atom.

I created a simple reproduction: https://codesandbox.io/p/sandbox/jotai-effect-infinite-loop-simple-forked-xgt3ck

// atomsWithQuery seems to be fine
const [queryAtom, queryStatusAtom] = atomsWithQueryAsync(async () => ({
  queryKey: ["queryKey"],
  queryFn: async () => {
    throw Error("Uh-oh!") 
  },
  retry: false,
}));

function MyComponent() {
  useAtom(queryStatusAtom) // infinite loop
}
dai-shi commented 10 months ago

Can @Leweyse take a look?

purecopy commented 10 months ago

For me it seems like the problem lies in the baseStatusAtom. I figured notifyResult() from the callback get's called over and over again.

https://github.com/jotaijs/jotai-tanstack-query/blob/721b0b3deffb4574798e334216e2ecb13aa44d6e/src/common.ts#L242-L268

wolfgang-cognify commented 10 months ago

We just ran into the same problem here. A fix is highly appreciated, since this currently blocks us from going to production with our app. Thank you!

DaniiiA commented 10 months ago

I also faced this issue a while ago! Thankfully someone brings up the topic now. Hopefully we can get a fix soon. That would be awesome 🙌

Kunama commented 10 months ago

I believe this issue is present in atomsWithInfiniteQuery as well. Seems to be linked to the change in this commit as downgrading to v0.7.1 causes the issue to resolve

dai-shi commented 10 months ago

@Aslemammad Can you help?

ShuviSchwarze commented 10 months ago

I thought I was going insane with this. In my use-case I was using atomsWithQueryAsync as a base atom then have another atom derives its state from the base atom for rendering. Couldn't figure out why it was looping, my initial thoughts was due to the fact that every get(baseAtom) call is triggering a rerun of the initial query and causing whatever is calling get(baseAtom) to rerun and loops. The problem with this atom looping occurs simply with an await inside queryFn and isn't limited to just throwing the Error. https://codesandbox.io/p/sandbox/jotai-effect-infinite-loop-simple-forked-kd3s84

sairion commented 10 months ago

Seems the most of APIs are reimplemented in https://github.com/jotaijs/jotai-tanstack-query/commit/e6f6cb78128b3d807d0abc29a17bbf462ce7fbaf and the status atom seems to be gone, so this is not a problem from 0.8.0?

kalijonn commented 9 months ago

I've taken a different approach in v0.8.0. atomsWithQueryAsync doesn't exist anymore.

This is how I see that pattern:

const idAtom = atom<Promise<string>>(async (get) => {
  const response = await fetch('/id/from/some/where')
  return response.json()
})

const userAtom = atomWithQuery((get) => {
  const id = get(unwrap(idAtom)) // id is of type string | undefined
  return {
    queryKey: ['users', id],
    queryFn: async ({ queryKey: [, id] }) => {
      const res = await fetch(
        `https://jsonplaceholder.typicode.com/users/${id}`
      )
      return res.json()
    },
    enabled: !!id, // queryFn will only fire when id is defined
  }
})

This is how dependent queries work in tanstack/query. Ref: Dependent Queries

ryanhaticus commented 8 months ago

I have this issue as well. :(

ShuviSchwarze commented 8 months ago

I have this issue as well. :(

This issue was resolved for me with 0.8.0, atomWithQueryAsync is removed now. Should probably update the version and migrate to the unwrap approach