jotaijs / jotai-form

Form atoms for Jotai
MIT License
134 stars 1 forks source link

input starts dirty when hydrated #26

Open jrnxf opened 5 months ago

jrnxf commented 5 months ago

If I have an atom defined like this

export const nameAtom = atomWithValidate("", {
  validate: (name) => {
    try {
      name.parse(name);
      return name;
    } catch (err: any) {
      throw err.issues;
    }
  },
});

and hydrate it via

useHydrateAtoms([[nameAtom, "hello world"]);

the input will start as dirty, since "hello world" !== "". If an atom is hydrated, what it is hydrated with should be the initial value that is checked against to determine if the input is dirty or not.

barelyhuman commented 5 months ago

Thanks for the report, i'll get back to you once I have time to check the reasoning

jrnxf commented 5 months ago

You bet! The reason I bring it up is because the current system works great when you start in an empty form, but if you want to start on a form with values already filled out, all the inputs with values with pre-filled data will be dirty, even though you never touched them yourself.

One idea would be to create a new function signatrue allow users to pass in a secondary value that can be used as the value to compare against, instead of just relying on the initial value. Something like this

existing

export const nameAtom = atomWithValidate("", {
  validate: (name) => { ... },
});

proposal

export const nameAtom = atomWithValidate("", "< this string will be used to compare against >", {
  validate: (name) => { ... },
});
jrnxf commented 5 months ago

Before you spend any time on this, I have a POC solution working great locally, I need to head out for the day, but can open a starter PR to get the conversation going!

daniel-rodrigue commented 5 months ago

If this idea goes ahead, personally I would propose a slightly different api signature:

export const nameAtom = atomWithValidate("", {
  initialValue: "< this string will be used to compare against >",
  validate: (name) => { ... },
});

This new option could help with this idea of passing an atom as the value.

barelyhuman commented 4 months ago

This should be doable once the react utils exports are done, can be followed here https://github.com/jotaijs/jotai-form/pull/27

barelyhuman commented 3 months ago

If this idea goes ahead, personally I would propose a slightly different api signature:

export const nameAtom = atomWithValidate("", {
  initialValue: "< this string will be used to compare against >",
  validate: (name) => { ... },
});

This new option could help with this idea of passing an atom as the value.

Sorry missed this,

in both API's it seems like you already have access to the value you wish to compare against, why not just pass it to the atom to begin with?

export const nameAtom = atomWithValidate("originalValue", {
  validate: (name) => { ... },
});

useHydrateAtoms was for SSR cases where the atoms are re-created and the original atom might already have been initialised, that isn't always the case with forms so it should be fine to just add in the original value as the first param, unless you are using the nameAtom as both a default store and also wish to add in initial value to the form after a data fetch.

For async atom creation, we don't have anything in this library right now which is why the original request makes sense, though the original jotai library doesn't signal a hydration on the atom which makes it hard for this to work with the original for SSR.

@dai-shi how bad of an idea is it if we export the hydrated store for the library to make use of?

dai-shi commented 3 months ago

how bad of an idea is it if we export the hydrated store for the library to make use of?

Sorry, I don't follow. Can you elaborate please? Is it about jotai-form, or jotai itself?

barelyhuman commented 3 months ago

how bad of an idea is it if we export the hydrated store for the library to make use of?

Sorry, I don't follow. Can you elaborate please? Is it about jotai-form, or jotai itself?

Jotai has a map of hydrated atoms that it uses to avoid double hydration on the same atom during SSR, would it be a problem if we exported a getter for that map?

dai-shi commented 3 months ago

I see. As you may guess, I would like to avoid exposing it. At the same time, I'm not confident that useHydrateAtoms cover various cases. Maybe it's time to reconsider the hydration scenario from scratch. (Though, I still don't follow the discussion. Can it be described without jotai-form context?)

barelyhuman commented 3 months ago

The discussion is about being able to re-initialize the form atom with a different value over a period of time (which I think is a valid requirement) but, the API's presented by the other developers seem to point in a direction where the value is already known at initialization which doesn't make sense since you could just pass it as the initial value instead

dai-shi commented 3 months ago

If useHydrateAtoms doesn't work, we generally suggest useEffect. We've been suggesting so, but we may need to explore a new pattern. If setAtom in render works without React warning, that might be a (new) solution.

barelyhuman commented 3 months ago

in this case the setAtom would create a Dirty form so yep, we need a different helper.

barelyhuman commented 3 months ago

We could do something like so to allow the RESET, and also add in a wrapper to avoid the awkwardness of using the constants https://github.com/jotaijs/jotai-form/pull/31