Frank HAWK
Frank HAWK

Reputation: 59

Uncontrolled Input Error in React Hook Form to an Null value from Redux

The data coming from Redux first returns null and then it comes back, by the way, useFrom could not update it, so I fixed it by using the reset function. Now when null data comes, the form resews, but this time I get such an error, I couldn't solve it.

Error:

A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component

https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable

It is actually explained here, I know this error, but I could not understand how to solve it from the field value in useForm.

My code:

// ** React Imports
import { useEffect, Fragment } from "react";

// ** Third Party Components
import { useForm, Controller } from "react-hook-form";

// ** Reactstrap Imports
import {
  Row,
  Col,
  Form,
  Card,
  Input,
  Label,
  Button,
  CardBody,
  CardTitle,
  CardHeader,
  FormFeedback,
} from "reactstrap";

// ** Store & Actions
import { useDispatch, useSelector } from "react-redux";
import { getUserProfile } from "@store/userProfile";

const UserProfile = () => {
  // ** Store Vars
  const dispatch = useDispatch();
  const { data } = useSelector((state) => state.userProfile);

  //** ComponentDidMount
  useEffect(() => {
      dispatch(getUserProfile());
  }, [dispatch]);

  // ** Hooks

  const defaultValues = {
    firstName: data?.firstName,
    lastName: data?.lastName,
    email: data?.email,
  };

  const {
    control,
    setValue,
    setError,
    handleSubmit,
    reset,
    formState: { errors },
  } = useForm({
    defaultValues,
  });

  //** ComponentDidMount
  useEffect(() => {
    reset({
      firstName: data?.firstName,
      lastName: data?.lastName,
      email: data?.email,
    });
  }, [data, reset]);

  return (
    <Fragment>
      <Card>
        <CardHeader className="border-bottom py-2">
          <CardTitle tag="h4">User Account</CardTitle>
        </CardHeader>
        <CardBody className="py-2 my-25">
          <Form className="mt-2 pt-50" onSubmit={handleSubmit(onSubmit)}>
            <Row>
              <Col sm="6" className="mb-1">
                <Label className="form-label" for="firstName">
                  First Name
                </Label>
                <Controller
                  name="firstName"
                  control={control}
                  render={({ field }) => (
                    <Input
                      id="firstName"
                      placeholder="John"
                      invalid={errors.firstName && true}
                      {...field}  //* *****
                    />
                  )}
                />
                {errors && errors.firstName && (
                  <FormFeedback>Please enter a valid First Name</FormFeedback>
                )}
              </Col>
              <Col sm="6" className="mb-1">
                <Label className="form-label" for="lastName">
                  Last Name
                </Label>
                <Controller
                  name="lastName"
                  control={control}
                  render={({ field }) => (
                    <Input
                      id="lastName"
                      placeholder="Doe"
                      invalid={errors.lastName && true}
                      {...field} //* *****
                    />
                  )}
                />
                {errors.lastName && (
                  <FormFeedback>Please enter a valid Last Name</FormFeedback>
                )}
              </Col>
              <Col sm="6" className="mb-1">
                <Label className="form-label" for="login-email">
                  Email
                </Label>
                <Controller
                  id="email"
                  name="email"
                  control={control}
                  render={({ field }) => (
                    <Input
                      type="email"
                      placeholder="[email protected]"
                      invalid={errors.email && true}
                      {...field} //* *****
                    />
                  )}
                />
                {errors.email && (
                  <FormFeedback>{errors.email.message}</FormFeedback>
                )}
              </Col>
              <Col className="mt-2" sm="12">
                <Button type="submit" className="me-1" color="primary">
                  Save changes
                </Button>
                <Button
                  color="secondary"
                  outline
                  onClick={() => {
                    setValue("firstName", data?.first_name);
                    setValue("lastName", data?.last_name);
                    setValue("email", data?.email);
                  }}
                >
                  Discard
                </Button>
              </Col>
            </Row>
          </Form>
        </CardBody>
      </Card>
    </Fragment>
  );
};

export default UserProfile;

Upvotes: 1

Views: 1645

Answers (1)

Frank HAWK
Frank HAWK

Reputation: 59

I added defaultValue prop and solved.

  <Col sm="6" className="mb-1">
                    <Label className="form-label" for="login-email">
                      Email
                    </Label>
                    <Controller
                      id="email"
                      name="email"
                      defaultValue="" // This is solution.
                      control={control}
                      render={({ field }) => (
                        <Input
                          type="email"
                          placeholder="[email protected]"
                          invalid={errors.email && true}
                          {...field} //* *****
                        />
                      )}
                    />
                    {errors.email && (
                      <FormFeedback>{errors.email.message}</FormFeedback>
                    )}
                  </Col>

Upvotes: 2

Related Questions