form-atoms / form-atoms

Atomic form primitives for Jotai

Home Page:https://codesandbox.io/s/getting-started-with-form-atoms-v2-ddhgq2?file=/src/App.tsx

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

What's the reason for limiting setting the initial value only once?

schiller-manuel opened this issue ยท comments

The docs say about useFieldInitialValue:

Initial values can only be set once per scope. Therefore, if the initial value used is changed during rerenders, it won't update the atom value.

But where does this limitation come from?
Why can't the initial value be updated as follows?

function useFieldInitialValue<Value>(
  fieldAtom: FieldAtom<Value>,
  initialValue?: Value,
  options?: UseAtomOptions,
): UseFieldInitialValue {
  const field = useAtomValue(fieldAtom, options);
  const store = useStore(options);

  useEffect(() => {
    if (initialValue === undefined) {
      return;
    }
    if (store.get(field._initialValue) === initialValue) {
      return;
    }
    if (!store.get(field.dirty)) {
      store.set(field.value, initialValue);
    }
    store.set(field._initialValue, initialValue);
  }, [store, field._initialValue, field.value, field.dirty, initialValue]);
}

what's the use case?

i think the biggest annoyance would be forcing people to use useMemo on their initial values (objects, arrays, etc) but i don't recall what other reason i had if there was one

I have an edit form where the data is loaded through react-query which uses an stale-while-revalidate caching strategy. This means the form is populated with possibly outdated data, then the data is reloaded in the background while the form is already mounted and then some fields' initial value may be updated.

BTW: could the "first" initial values be set using (useHydrateAtoms)[https://github.com/pmndrs/jotai/blob/main/src/react/utils/useHydrateAtoms.ts] and only subsequent changes to the initial value would be done through useEffect?

Hmm that's a reasonable case. I think I might have used useHydrateAtoms in an older version but the API didn't work with things like the the store.get(field.dirty) check. You cool to submit a PR?

do you think that equality check I added in the above code is necessary?

Should the expected behavior for going from defined to undefined be that the value clears? It seems so, right? In that case the check would have to go

I played around with removing initialValue === undefined, turns out would cause issues if one uses useFieldInitialValue in combination with e.g. useInputField as the latter would issue a call to useFieldInitialValue with initialValue=undefined.

So we would need another value as a "reset" signal, how about RESET?

export function useFieldInitialValue<Value>(
  fieldAtom: FieldAtom<Value>,
  initialValue?: Value | typeof RESET,
  options?: UseAtomOptions
): UseFieldInitialValue {
  const field = useAtomValue(fieldAtom, options);
  const store = useStore(options);

  React.useEffect(() => {
    if (initialValue === undefined) {
      return;
    }
    if (!store.get(field.dirty)) {
      store.set(field.value, initialValue);
    }
    store.set(field._initialValue, initialValue);
  }, [store, field._initialValue, field.value, field.dirty, initialValue]);
}

๐ŸŽ‰ This issue has been resolved in version 3.2.0 ๐ŸŽ‰

The release is available on:

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€

@schiller-manuel I'm revisiting the hydration as the current hook fails to initialize the form when rendered on the server (Next.js)

BTW: could the "first" initial values be set using (useHydrateAtoms)[https://github.com/pmndrs/jotai/blob/main/src/react/utils/useHydrateAtoms.ts] and only subsequent changes to the initial value would be done through useEffect?

https://github.com/form-atoms/field/blob/main/src/hooks/use-hydrate-field/useHydrateField.ts