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

Initial atom state #119

Closed
istarkov opened this issue Oct 9, 2020 · 8 comments
Closed

Initial atom state #119

istarkov opened this issue Oct 9, 2020 · 8 comments
Labels
has snippet This issue includes code snipppets as solutions or workarounds

Comments

@istarkov
Copy link

istarkov commented Oct 9, 2020

Currently the most issue I see with atoms is initial atom state which especially on server cant be inside any global objects ie localStorage etc. (setEffect is not working on server too)

Creating atoms and passing them through a context - loss of main advantages (u would need to create dependent atoms in context etc)

Probably passing Provider value to atom on initial call could solve this?

I.e.

// atom already have getter fn as param so I call atom with state dependent on context subatom.

const myAtom = subatom(ctx => ctx.someVal)

....
// in some component

<InitialJotaiValueProvider value={{ someVal: 123 }}> ...

Or probably some other beautiful api can be available.

PS: Api like above can be typed well like

const { InitialValueProvider, subatom} = createBlaBla<ValueType>()
@dai-shi
Copy link
Member

dai-shi commented Oct 9, 2020

Hi, thanks for chiming in.

I'm not quite sure if I understand the problem. Would you elaborate with code snippet?

For localStorage, we could read it when creating an atom, because it's sync.

const fooAtom = atom(localStorage.getItem('foo') || 'fooDefault')

(but, it sounds like something different from what you mention.)

For, nextjs getServerProps, we need some hacks, so far I've got these:
https://codesandbox.io/s/nextjs-with-jotai-5ylrj
https://codesandbox.io/s/nextjs-with-jotai-async-pm0l8

Probably passing Provider value to atom on initial call could solve this?
Or probably some other beautiful api can be available.

Yeah, there might be room for improvement. I'd prefer to solve it with (derived) atoms, if possible though.

@istarkov
Copy link
Author

istarkov commented Oct 9, 2020

On server rendering state can come and come from db etc. We can't use examples above, db state isnt known at module level and cant be cached into global vars as requests and io is processed in event loop and you cant be sure that global vars has results from current request.

@dai-shi
Copy link
Member

dai-shi commented Oct 9, 2020

Do you have a query for the DB which can build from the current request?
What about something like this?

const Component = ({ request }) => {
  const query = useMemo(() => buildQuery(request), [request])
  const queryAtom = useMemo(() => atom(async () => queryDb(query)), [query])
  const result = useAtom(queryAtom)
  // ...
}

@istarkov
Copy link
Author

istarkov commented Oct 9, 2020

Once u created atom definition inside component you need to share it between all components where it used using Context or props. Also instead of defining atom at place where its needed - at Component module, you need to define it now at some upper node in the tree.
IMO most beauty and simplicity of idea lost :-(

@dai-shi
Copy link
Member

dai-shi commented Oct 9, 2020

Ah, yes, got it. we need to pass the atom using context or props.

If we have uid, session id, or request object, we could use Map/WeakMap at module level
to store atom for each uid, and share it between components. atomFamily might work, if we could remove unused atoms.

@istarkov
Copy link
Author

istarkov commented Oct 9, 2020

Yep, WeakMaps are so rarely used that I always forget about. Just a small wrapper around and it can work well. Thank you.

@dai-shi
Copy link
Member

dai-shi commented Oct 9, 2020

You are welcome!

For someone interested, it's like this.

const weakAtomFamily = (initializeRead, initializeWrite) => {
  const atoms = new WeakMap()
  return (obj) => {
    if (atoms.has(obj)) return atoms.get(obj)
    const newAtom = atom(initializeRead(obj), initializeWrite && initializeWrite(obj))
    atoms.set(obj, newAtom)
    return newAtom
  }
}

@dai-shi dai-shi added the has snippet This issue includes code snipppets as solutions or workarounds label Oct 15, 2020
@dai-shi
Copy link
Member

dai-shi commented Nov 1, 2020

#158 added shouldRemove. There can still be cases weakAtomFamily works better.
We can add it to utils if someone suggests some use cases.

For now, I don't think we have any actions for this issue, so closing this.

@dai-shi dai-shi closed this as completed Nov 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has snippet This issue includes code snipppets as solutions or workarounds
Projects
None yet
Development

No branches or pull requests

2 participants