pmndrs / jotai

👻 Primitive and flexible state management for React
https://jotai.org
MIT License
18.3k stars 590 forks source link

onMount doesn't seem to fire for suspended atoms #1437

Closed tpavlu closed 1 year ago

tpavlu commented 1 year ago

I was trying to use Jotai to abstract away some data access that was both fetching data and creating a subscription that would keep that data synchronized while the atom was mounted anywhere. I noticed that my onMount function wasn't being called.

The general approach I was using was

const Family = atomFamily((args: string) => {
  const atom = atomWithDefault(() => new Promise<>(() => {}))
  atom.onMount = () => {
    // This gets the initial data and then subsequent updates. It returns an unsubscribe call
    return service.subscribe()
  }
})

Here is a code sandbox isolating the issue https://codesandbox.io/s/awesome-architecture-rzvc9p?file=/src/App.tsx

I looked into the react query integration and saw that they were triggering the query in the 'get' function for the atom as well as on mount to work around this issue. I don't know a ton of information as to the why here but i suspect the onMount logic is tied to the component lifecycle in a way where it executes after the throw Promise<>() logic occurs, this prevents the onMount from executing.

It would be awesome if either a) onMount would always fire even if suspended or b) this could be documented an ideally there was hook like onSuspended or something

Please LMK if there is any more context I can provide. If I dive into the source and have more of recommended solution I will also post that here.

dai-shi commented 1 year ago

Hi, onMount is basically a syntax for useEffect(..., []). And, it's the designed behavior by React. Unfortunately, doing effects on suspend is technically impossible, because we can never run cleanups. (well, in the far future, we might explore FinalizationRegistry, but that may not work as expected anyway.)

I will close this issue as nothing is actionable for now.


Now, the question about how to do it in reality is still valid. As you see, jotai/query does something hacky. We basically do the same thing in jotai/urql and some other new integrations. So, there's work on going to isolate the hack code out of those integrations. #1435 is the first one still in progress. tldr is use atomWithObservable in jotai/utils.

Once we made some progress, we should add a new guide in docs about this pattern.