Skip to content

Commit 021e149

Browse files
authored
refactor: use the useWatch from react-hook-form to get around the react-compiler memoization issues (#376)
the react-compiler doesn't play well with the `form.watch` api as it breaks the rules-of-react in an unobvious way, thus loosing the reactivity that was intended. to get around this you need to wrap it in `useMemo` to trick the compilter. this change consumes the `form.control` in the provided `useWatch` hook by `react-hook-form` to maintain the reactivity of the original api without breaking the rules-of-react, thus letting the react-compilter work flawlessly without any hacks.
1 parent 5f737ce commit 021e149

File tree

8 files changed

+44
-87
lines changed

8 files changed

+44
-87
lines changed

src/components/add-rental/customer-information/customer-stage.tsx

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from "react";
22
import { zodResolver } from "@hookform/resolvers/zod";
3-
import { useForm } from "react-hook-form";
3+
import { useForm, useWatch } from "react-hook-form";
44
import { useTranslation } from "react-i18next";
55
import { z } from "zod";
66

@@ -108,12 +108,7 @@ export const CustomerStage = ({
108108
values: customerInformation ? values : undefined,
109109
});
110110

111-
const form_dob = React.useMemo(
112-
() => form.watch("dateOfBirth"),
113-
// eslint-disable-next-line react-compiler/react-compiler
114-
// eslint-disable-next-line react-hooks/exhaustive-deps
115-
[form.watch("dateOfBirth")]
116-
);
111+
const form_dob = useWatch({ control: form.control, name: "dateOfBirth" });
117112

118113
return (
119114
<Form {...form}>

src/components/add-rental/rates-and-charges/rates-stage.tsx

+15-25
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import * as React from "react";
22
import { zodResolver } from "@hookform/resolvers/zod";
33
import { useQuery } from "@tanstack/react-query";
4-
import { useForm, type FormState, type UseFormRegister } from "react-hook-form";
4+
import {
5+
useForm,
6+
useWatch,
7+
type FormState,
8+
type UseFormRegister,
9+
} from "react-hook-form";
510
import { useTranslation } from "react-i18next";
611
import { useAuth } from "react-oidc-context";
712

@@ -84,38 +89,23 @@ export const RatesStage = (props: RatesStageProps) => {
8489
}, [rate]),
8590
});
8691

87-
React.useEffect(() => {
88-
if (rate) {
89-
form.reset(rate);
90-
}
91-
}, [form, rate, rate?.rateName, rateName]);
92-
93-
const isDayRate = React.useMemo(
94-
() => form.watch("isDayRate"),
95-
// eslint-disable-next-line react-compiler/react-compiler
96-
// eslint-disable-next-line react-hooks/exhaustive-deps
97-
[form.watch("isDayRate")]
98-
);
99-
const isWeekDayRate = React.useMemo(
100-
() => form.watch("isDayWeek"),
101-
// eslint-disable-next-line react-compiler/react-compiler
102-
// eslint-disable-next-line react-hooks/exhaustive-deps
103-
[form.watch("isDayWeek")]
104-
);
92+
const isDayRate = useWatch({ control: form.control, name: "isDayRate" });
93+
const isWeekDayRate = useWatch({ control: form.control, name: "isDayWeek" });
94+
const totalDays = useWatch({ control: form.control, name: "totalDays" });
10595

106-
const totalDays = React.useMemo(
107-
() => form.watch("totalDays"),
108-
// eslint-disable-next-line react-compiler/react-compiler
109-
// eslint-disable-next-line react-hooks/exhaustive-deps
110-
[form.watch("totalDays")]
111-
);
11296
const rentalDays = totalDays ?? 0;
11397

11498
const commonFormProps: CommonRatesFormProps = {
11599
registerFn: form.register,
116100
formState: form.formState,
117101
};
118102

103+
React.useEffect(() => {
104+
if (rate) {
105+
form.reset(rate);
106+
}
107+
}, [form, rate, rate?.rateName, rateName]);
108+
119109
return (
120110
<Form {...form}>
121111
{!isSupportingInfoAvailable && (

src/components/add-rental/rental-information/duration-stage.tsx

+13-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from "react";
22
import { zodResolver } from "@hookform/resolvers/zod";
33
import { useQuery } from "@tanstack/react-query";
4-
import { useForm } from "react-hook-form";
4+
import { useForm, useWatch } from "react-hook-form";
55
import { useTranslation } from "react-i18next";
66
import { useAuth } from "react-oidc-context";
77
import { z } from "zod";
@@ -139,7 +139,10 @@ export const DurationStage = ({
139139
);
140140
const agreementTypesList = agreementTypeData.data ?? [];
141141

142-
const currentAgreementType = form.watch("agreementType");
142+
const currentAgreementType = useWatch({
143+
control: form.control,
144+
name: "agreementType",
145+
});
143146
const agreementNumberQuery = useQuery(
144147
fetchAgreementGeneratedNumberOptions({
145148
auth: authParams,
@@ -148,18 +151,14 @@ export const DurationStage = ({
148151
})
149152
);
150153

151-
const form_checkoutDate = React.useMemo(
152-
() => form.watch("checkoutDate"),
153-
// eslint-disable-next-line react-compiler/react-compiler
154-
// eslint-disable-next-line react-hooks/exhaustive-deps
155-
[form.watch("checkoutDate")]
156-
);
157-
const form_checkinDate = React.useMemo(
158-
() => form.watch("checkinDate"),
159-
// eslint-disable-next-line react-compiler/react-compiler
160-
// eslint-disable-next-line react-hooks/exhaustive-deps
161-
[form.watch("checkinDate")]
162-
);
154+
const form_checkoutDate = useWatch({
155+
control: form.control,
156+
name: "checkoutDate",
157+
});
158+
const form_checkinDate = useWatch({
159+
control: form.control,
160+
name: "checkinDate",
161+
});
163162

164163
const handleCheckoutDateChange = (date: Date) => {
165164
const previousCheckoutDate = form_checkoutDate;

src/components/add-rental/rental-information/vehicle-stage.tsx

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from "react";
22
import { zodResolver } from "@hookform/resolvers/zod";
33
import { useQuery } from "@tanstack/react-query";
4-
import { useForm } from "react-hook-form";
4+
import { useForm, useWatch } from "react-hook-form";
55
import { useTranslation } from "react-i18next";
66
import { useAuth } from "react-oidc-context";
77
import { z } from "zod";
@@ -92,18 +92,11 @@ export const VehicleStage = ({
9292
values: vehicleInformation ? values : undefined,
9393
});
9494

95-
const formVehicleTypeId = React.useMemo(
96-
() => form.watch("vehicleTypeId"),
97-
// eslint-disable-next-line react-compiler/react-compiler
98-
// eslint-disable-next-line react-hooks/exhaustive-deps
99-
[form.watch("vehicleTypeId")]
100-
);
101-
const formVehicleId = React.useMemo(
102-
() => form.watch("vehicleId"),
103-
// eslint-disable-next-line react-compiler/react-compiler
104-
// eslint-disable-next-line react-hooks/exhaustive-deps
105-
[form.watch("vehicleId")]
106-
);
95+
const formVehicleTypeId = useWatch({
96+
control: form.control,
97+
name: "vehicleTypeId",
98+
});
99+
const formVehicleId = useWatch({ control: form.control, name: "vehicleId" });
107100

108101
//
109102
const vehicleTypesData = useQuery(

src/routes/_auth/(dashboard)/-components/widget-grid/widgets/quick-lookup.tsx

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from "react";
22
import { zodResolver } from "@hookform/resolvers/zod";
33
import { useMutation, useQueryClient } from "@tanstack/react-query";
44
import { useNavigate } from "@tanstack/react-router";
5-
import { useForm } from "react-hook-form";
5+
import { useForm, useWatch } from "react-hook-form";
66
import { useTranslation } from "react-i18next";
77
import { toast } from "sonner";
88
import { z } from "zod";
@@ -90,12 +90,7 @@ export default function SalesStatusWidget(props: CommonWidgetProps) {
9090
shouldUnregister: true,
9191
});
9292

93-
const accessor = React.useMemo(
94-
() => form.watch("accessor"),
95-
// eslint-disable-next-line react-compiler/react-compiler
96-
// eslint-disable-next-line react-hooks/exhaustive-deps
97-
[form.watch("accessor")]
98-
);
93+
const accessor = useWatch({ control: form.control, name: "accessor" });
9994

10095
const customers = useMutation({
10196
mutationFn: fetchCustomersSearchListFn,

src/routes/_auth/(settings)/-components/application/location-edit-dialog.tsx

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import { zodResolver } from "@hookform/resolvers/zod";
33
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4-
import { useForm } from "react-hook-form";
4+
import { useForm, useWatch } from "react-hook-form";
55
import { useTranslation } from "react-i18next";
66
import { toast } from "sonner";
77

@@ -346,12 +346,7 @@ function LocationForm(props: LocationFormProps) {
346346
},
347347
});
348348

349-
const countryId = React.useMemo(
350-
() => form.watch("countryId"),
351-
// eslint-disable-next-line react-compiler/react-compiler
352-
// eslint-disable-next-line react-hooks/exhaustive-deps
353-
[form.watch("countryId")]
354-
);
349+
const countryId = useWatch({ control: form.control, name: "countryId" });
355350

356351
const locationsQuery = useQuery(
357352
fetchLocationsListOptions({

src/routes/_auth/(settings)/-components/application/role-edit-dialog.tsx

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from "react";
22
import { zodResolver } from "@hookform/resolvers/zod";
33
import { AccordionItem } from "@radix-ui/react-accordion";
44
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5-
import { useForm } from "react-hook-form";
5+
import { useForm, useWatch } from "react-hook-form";
66
import { useTranslation } from "react-i18next";
77
import { toast } from "sonner";
88
import { z } from "zod";
@@ -375,12 +375,7 @@ function RoleForm(props: {
375375
},
376376
});
377377

378-
const templateId = React.useMemo(
379-
() => form.watch("templateId"),
380-
// eslint-disable-next-line react-compiler/react-compiler
381-
// eslint-disable-next-line react-hooks/exhaustive-deps
382-
[form.watch("templateId")]
383-
);
378+
const templateId = useWatch({ control: form.control, name: "templateId" });
384379

385380
const roleQuery = useQuery(
386381
fetchRoleByIdOptions({

src/routes/_auth/(settings)/settings.profile.tsx

+2-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
useSuspenseQuery,
77
} from "@tanstack/react-query";
88
import { createFileRoute } from "@tanstack/react-router";
9-
import { useForm, UseFormReturn } from "react-hook-form";
9+
import { useForm, useWatch, type UseFormReturn } from "react-hook-form";
1010
import { useTranslation } from "react-i18next";
1111
import { toast } from "sonner";
1212

@@ -334,12 +334,7 @@ const COPY_TIMEOUT = 1500;
334334

335335
function UsernameBlock({ form }: BlockProps) {
336336
const { t } = useTranslation();
337-
const username = React.useMemo(
338-
() => form.watch("userName"),
339-
// eslint-disable-next-line react-compiler/react-compiler
340-
// eslint-disable-next-line react-hooks/exhaustive-deps
341-
[form.watch("userName")]
342-
);
337+
const username = useWatch({ control: form.control, name: "userName" });
343338

344339
const [hidden, setHidden] = React.useState(false);
345340
const [_, copy] = useCopyToClipboard();

0 commit comments

Comments
 (0)