Review
Hive inspection edit form resets defaults after load
Apiary techs open an existing hive inspection and the Save button stays disabled even after they change mite count, because defaultValues only applied on mount when the query was still empty. Wire reset(values) when the inspection query succeeds so RHF treats server data as the new defaults and dirtyFields/isDirty reflect real edits.
RHFTier 2react-hook-formresetdirtyFieldsasync
Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.
components/apiary/HiveInspectionForm.tsx+12-6
| 1 | 1 | import { useEffect } from "react"; | |
| 2 | 2 | import { useForm } from "react-hook-form"; | |
| 3 | 3 | import { useQuery } from "@tanstack/react-query"; | |
| 4 | 4 | import { fetchHiveInspection, updateHiveInspection } from "@/api/apiary"; | |
| 5 | 5 | ||
| 6 | 6 | type InspectionForm = { | |
| 7 | 7 | broodPattern: string; | |
| 8 | 8 | miteCount: number; | |
| 9 | 9 | notes: string; | |
| 10 | 10 | }; | |
| 11 | 11 | ||
| 12 | 12 | export function HiveInspectionForm({ inspectionId }: { inspectionId: string }) { | |
| 13 | 13 | const { data, isSuccess } = useQuery({ | |
| 14 | 14 | queryKey: ["hive-inspection", inspectionId], | |
| 15 | 15 | queryFn: () => fetchHiveInspection(inspectionId), | |
| 16 | 16 | }); | |
| 17 | 17 | ||
| 18 | 18 | const { | |
| 19 | 19 | register, | |
| 20 | 20 | handleSubmit, | |
| 21 | + | reset, | |
| 21 | 22 | formState: { dirtyFields, isDirty }, | |
| 22 | 23 | } = useForm<InspectionForm>({ | |
| 23 | - | // data is undefined on first render — these stick as empty forever | |
| 24 | - | defaultValues: { | |
| 25 | - | broodPattern: data?.broodPattern ?? "", | |
| 26 | - | miteCount: data?.miteCount ?? 0, | |
| 27 | - | notes: data?.notes ?? "", | |
| 28 | - | }, | |
| 24 | + | defaultValues: { broodPattern: "", miteCount: 0, notes: "" }, | |
| 29 | 25 | }); | |
| 30 | 26 | ||
| 27 | + | // Promote server payload to form defaults so dirtyFields tracks user edits only. | |
| 28 | + | useEffect(() => { | |
| 29 | + | if (!isSuccess || !data) return; | |
| 30 | + | reset({ | |
| 31 | + | broodPattern: data.broodPattern, | |
| 32 | + | miteCount: data.miteCount, | |
| 33 | + | notes: data.notes, | |
| 34 | + | }); | |
| 35 | + | }, [isSuccess, data, reset]); | |
| 36 | + | ||
| 31 | 37 | return ( | |
| 32 | 38 | <form onSubmit={handleSubmit((v) => updateHiveInspection(inspectionId, v))}> | |
| 33 | 39 | <input type="number" {...register("miteCount", { valueAsNumber: true })} /> | |
| 34 | 40 | {dirtyFields.miteCount ? <span>unsaved mite count</span> : null} | |
| 35 | 41 | <button type="submit" disabled={!isDirty}>Save inspection</button> | |
| 36 | 42 | </form> | |
| 37 | 43 | ); | |
| 38 | 44 | } |