jotaijs / jotai-scope

MIT License
55 stars 4 forks source link

Initializing state on render for scoped primitive atoms #6

Closed yf-yang closed 10 months ago

yf-yang commented 10 months ago

All right, after #5, when actually applying jotai-scope, I found that "Initializing state on render" problem is much more important for scoped primitive atoms (just like how we put a value to React.Context.Provider).

Now there are two things to do:

  1. Patch useHydrateAtoms, otherwise there is no way to initialize scoped atom other than the default initializer
  2. If I got it right, bunshi's ScopeProvider's option (that withUniqueScope/withScope, etc.) offers a syntax sugar to initialize scope value on render. We need some similar API that wraps both ScopeProvider and useHydrateAtoms (And make it more intuitive).
yf-yang commented 10 months ago

I am currently using a workaround:

function Component() {
  return (
    <ScopeProvider atoms={[anAtom]}>
      <Wrapper value={value}>
        <ChildComponent/>
      </Wrapper>
    </ScopeProvider>
  );
}

function Wrapper({value, children}) {
  const setAnAtom = useSetAtom(anAtom);
  useEffect(() => {
    setAnAtom(value);
  }, [value])
  return <>{children}</>;
}

The drawback is that the effect callback is executed asynchronously.

dai-shi commented 10 months ago

Nice catch. Let me work on 1.

For 2, I think it's a userland work. It's similar to that HydrateAtoms is a userland solution. https://github.com/pmndrs/jotai/blob/075bd5b77e414597bdc270549eeb9e0650cd85e3/docs/guides/initialize-atom-on-render.mdx#L59-L63

yf-yang commented 10 months ago

Emmm, then that would be something like:

function ScopeProviderWithInitializer({ children, atomPairs }) {
  const atoms = atomPairs.map(([anAtom]) => anAtom);
  return (
    <ScopeProvider atoms={atoms}>
      <AtomsHydrator atomPairs={atomPairs}>
        {children}
      </AtomsHydrator>
    </ScopeProvider>
  );
}

function AtomsHydrator({ children, atomPairs }) {
  useHydrateAtoms(atomPairs);
  return <>{children}</>;
}

Looks like the two line component AtomsHydrator could be refactored.