pmndrs / jotai

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

utils - Atom not found #240

Closed jcane86 closed 3 years ago

jcane86 commented 3 years ago

I have a utility component where I create some atoms, and maybe set some values depending on props and other stuff, but I don't need the values, I export the value getters separately.

So I am using useUpdateAtom in this component instead of useAtom, as I assume it would have some performance benefits.

The problem is always get this error:

[Bug] Atom state not found. Please file an issue with repro: updateAtomState 
{key: 1, init: 1, read: ƒ (), write: ƒ ()}

I tracked this down and it appears there is some setup work to initialize the atom's state that is done in useAtom, but when using useUpdateAtom, this init is only done on the read only copy of the atom. https://github.com/pmndrs/jotai/blob/072e26a41f590adf6b7e8e8683d48cc3d30caddb/src/utils/useUpdateAtom.ts#L11

In that line, useAtom (and the init contained in it) is run for writeOnlyAtom, but not for anAtom. The init I think is missing is here: https://github.com/pmndrs/jotai/blob/072e26a41f590adf6b7e8e8683d48cc3d30caddb/src/core/useAtom.ts#L66

I have a minimal repro here: https://codesandbox.io/s/jotai-atom-state-not-found-9dm2t just push the button and look at the console =)

BTW, thanks for the library, its great!

dai-shi commented 3 years ago

Hi! Thanks for using the library! We are about to release a new version with many internal improvements soon, which might solve the issue. Will you try with the work-in-progress build? https://ci.codesandbox.io/status/pmndrs/jotai/pr/239/builds/83096

  "dependencies": {
     "jotai": "https://pkg.csb.dev/pmndrs/jotai/commit/f7c2d2e2/jotai",

I tried your sandbox with this, which seems fine. But, not sure if it works for your real app.

jcane86 commented 3 years ago

お疲れ様です Thanks a lot for the quick reply..

I'm afraid I'm still having the same issue in my app, not sure why it is working in the codesandbox... I'll try to update it with the new failure.

jcane86 commented 3 years ago

@dai-shi I think I found my issue, but it might be my fault.

I am trying to store a function inside an atom. I have tried doing it like:

  const setCallback = useUpdateAtom(callbackAtom);
  React.useEffect(() => {
    setCallback(callback);
  }, [callback, setCallback]);
  const setCallback = useUpdateAtom(callbackAtom);
  React.useEffect(() => {
    setCallback(() => callback);
  }, [callback, setCallback]);

The second approach works in terms of storing the callback inside the atom, the first one doens't work, I assume it is interpreting my callback as an updater function. Unfortunately both of these approaches give this warning:

index.js:401 [Bug] writeAtomState no state {init: null, toString: ƒ, read: ƒ, write: ƒ}

Are callbacks or functions a supported usecase?

dai-shi commented 3 years ago

Good morning.

I assume it is interpreting my callback as an updater function.

Exactly. It would behave the same with React.useState.

You could change the behavior with a derived atom.

const callbackAtom = atom(() => null)
const derivedCallbackAtom = atom(
  get => get(callbackAtom),
  (_get, set, nextCallback) => set(callbackAtom, nextCallback)
)

Unfortunately both of these approaches give this warning:

Would you create a small repro in codesandbox? Oh, I think I get it. You are probably trying to update an atom that is never used. Currently, an atom must be used explicitly or dependent with other atoms. You can't update it before the initialization. We discuss about this behavior recently, and hope to make a better documentation, give better warning message or fix it fundamentally if possible.

jcane86 commented 3 years ago

ah, I see.. I thought that might be the case.. I will make sure to initialize them before using them. Thank you!