I'm using React Hook Form with three input fields:
I want the night difference to update automatically whenever the start or end date changes.
Is there a way to update the night difference without using onChange, but by placing the logic inside register?
import "./styles.css";
import { useForm } from "react-hook-form";
export default function App() {
const { register, getValues, setValue } = useForm();
return (
<div className="App">
<form>
<label>Start Date</label>
<input
type="date"
id="startDate"
{...register("startDate", {
required: "This field is required",
})}
onChange={(e) =>
setValue(
"numNights",
Math.floor(
(new Date(getValues().endDate) - new Date(e.target.value)) /
(1000 * 60 * 60 * 24)
) || ""
)
}
/>
<label>End Date</label>
<input
type="date"
id="endDate"
{...register("endDate", {
required: "This field is required",
validate: (value) => {
if (value <= getValues().startDate) {
return "End date must be after the start date";
}
},
})}
onChange={(e) =>
setValue(
"numNights",
Math.floor(
(new Date(e.target.value) - new Date(getValues().startDate)) /
(1000 * 60 * 60 * 24)
)
)
}
/>
<label>Nights</label>
<input type="text" id="numNights" readOnly {...register("numNights")} />
</form>
</div>
);
}
You can use useWatch
to observe changes in the date fields.
By using useEffect
, you can then calculate the difference in days (nights) whenever either the start or end date is changed.
startDate
and endDate
fieldsimport { useForm, useWatch } from "react-hook-form";
import { useEffect } from "react";
export default function App() {
const { register, getValues, setValue, control } = useForm();
const startDate = useWatch({ control, name: "startDate" });
const endDate = useWatch({ control, name: "endDate" });
const calculateNights = (start, end) => {
if (start && end) {
const diffDays = Math.floor(
(new Date(end) - new Date(start)) / (1000 * 60 * 60 * 24)
);
return diffDays > 0 ? diffDays : "";
}
return "";
};
useEffect(() => {
setValue("numNights", calculateNights(startDate, endDate));
}, [startDate, endDate, setValue]);
return (
<form>
<label>Start Date</label>
<input type="date" {...register("startDate", { required: true })} />
<label>End Date</label>
<input type="date" {...register("endDate", { required: true })} />
<label>Nights</label>
<input type="text" readOnly {...register("numNights")} />
</form>
);
}