Reputation: 59
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
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