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

[Bug]: Value of useControlField is undefined on first render #351

Open
1 of 4 tasks
AlexanderKulia opened this issue Feb 25, 2024 · 4 comments
Open
1 of 4 tasks

[Bug]: Value of useControlField is undefined on first render #351

AlexanderKulia opened this issue Feb 25, 2024 · 4 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request

Comments

@AlexanderKulia
Copy link

AlexanderKulia commented Feb 25, 2024

Which packages are impacted?

  • remix-validated-form
  • @remix-validated-form/with-zod
  • @remix-validated-form/with-yup
  • zod-form-data

What version of these packages are you using?

  • @remix-validated-form/with-zod": "^2.0.7"
  • "remix-validated-form": "^5.1.5"
  • "zod": "^3.22.4"
  • "zod-form-data": "^2.0.2"

Please provide a link to a minimal reproduction of the issue.

https://github.com/AlexanderKulia/use-control-field-example

Steps to Reproduce the Bug or Issue

  1. Clone repo
  2. Run yarn install
  3. Run yarn dev
  4. Open browser, open console
  5. Refresh page, field is undefined before its values changes to "alex"

Expected behavior

I expected that the field's initial value is set to whatever is passed in defaultValues similar to useState<string>("alex"). Am I doing something wrong? Because with this behavior I have to change the type to string | undefined and handle undefined which is annoying in complicated dynamic forms

Screenshots or Videos

No response

Platform

  • OS: macOS, Linux
  • Browser: Chrome
  • Version: 121.0.6167.189

Additional context

No response

@AlexanderKulia AlexanderKulia added the bug Something isn't working label Feb 25, 2024
@tukiminya
Copy link

Have you tried using useEffect?

export const MyForm = () => {
  const [value, setValue] = useControlField(
    "myField",
    "myForm"
  );

  useEffect(() => {
    // Now we can update the value of the field
    // for whatever reason we need.
    setValue("Some value");
  });

  return (
    <ValidatedForm validator={myValidator} id="myForm">
      <MyInput
        name="myField"
        // This assumes your input component
        // has a `value` and `onChange` prop
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
    </ValidatedForm>
  );
};

Example in here:
https://www.remix-validated-form.io/reference/use-control-field

@AlexanderKulia
Copy link
Author

AlexanderKulia commented Feb 26, 2024

I'm not quite sure what the example demostrates. I've added useEffect to my example repo and it does not seem to do anything regardless of how I set it up. In the particular example in the docs useEffect is executed on every render (deps array is missing) which does not make sense and leads to infinite recursion

image

P.S. I had a small mistake in my initial example: value and onChange were missing. It's corrected now, but it doesn't change the fact that the value is undefined on first render. Moreover, now I get this

image

@mschipperheyn
Copy link

I consider it a bug as well. The workaround is to read the defaultValue from useField and set the form element value as value={value ?? defaultValue} where value would be read through useControlField.

@airjp73
Copy link
Owner

airjp73 commented Mar 6, 2024

This happens only when using useControlField outside the context of the form itself. This hook has the same limitations mentioned in the "Other Considerations" section on this page. Though admittedly it doesn't look like I documented that anywhere.

I think a potential API improvement we could make here is to allow passing a default value directly into the hook like you mentioned.

But this is more of an intentional (if unfortunate) trade-off of the current API, rather than a bug. If you think about it, in code that looks like this, it's impossible for the useControlField hook to know anything about the default values of the form.

const { defaultValues } = useLoaderData();

const [value, setValue] = useControlField("myField");

return (
  <ValidatedForm
    defaultValues={defaultValues}
    // ...etc
  />
)

There are 3 main ways to fix the issue your observing.

Manually provide a default

const [firstName = defaultValues.firstName, setFirstName] = useControlField("firstName");

Use setFormDefaults instead of the defaultValues prop

export const loader = async () => {
  return setFormDefaults(formId, {
    firstName: "alex",
    lastName: "k",
  });
};

Call useControlField inside the form

const ControlledInput = (props) => {
  const [value, setValue] = useControlField(props.name);
  return (
    <ValidatedInput
      value={value}
      onChange={e => setFirstName(e.target.value)}
      {...props}
    />
  );
}

@airjp73 airjp73 added documentation Improvements or additions to documentation enhancement New feature or request and removed bug Something isn't working labels Mar 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants