From 4dfec0f18f9dfe69c4576e57fcb1a9daf974f055 Mon Sep 17 00:00:00 2001 From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com> Date: Sun, 23 Jun 2024 00:20:32 +1200 Subject: [PATCH] refactor: use the `useWatch` from react-hook-form to get around the react-compiler memoization issues 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. --- .../customer-information/customer-stage.tsx | 9 +---- .../rates-and-charges/rates-stage.tsx | 40 +++++++------------ .../rental-information/duration-stage.tsx | 27 ++++++------- .../rental-information/vehicle-stage.tsx | 19 +++------ .../widget-grid/widgets/quick-lookup.tsx | 9 +---- .../application/location-edit-dialog.tsx | 9 +---- .../application/role-edit-dialog.tsx | 9 +---- .../_auth/(settings)/settings.profile.tsx | 9 +---- 8 files changed, 44 insertions(+), 87 deletions(-) diff --git a/src/components/add-rental/customer-information/customer-stage.tsx b/src/components/add-rental/customer-information/customer-stage.tsx index b4eb2bfb..f9a148f3 100644 --- a/src/components/add-rental/customer-information/customer-stage.tsx +++ b/src/components/add-rental/customer-information/customer-stage.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { z } from "zod"; @@ -108,12 +108,7 @@ export const CustomerStage = ({ values: customerInformation ? values : undefined, }); - const form_dob = React.useMemo( - () => form.watch("dateOfBirth"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("dateOfBirth")] - ); + const form_dob = useWatch({ control: form.control, name: "dateOfBirth" }); return (
diff --git a/src/components/add-rental/rates-and-charges/rates-stage.tsx b/src/components/add-rental/rates-and-charges/rates-stage.tsx index 24d7d29a..02b90752 100644 --- a/src/components/add-rental/rates-and-charges/rates-stage.tsx +++ b/src/components/add-rental/rates-and-charges/rates-stage.tsx @@ -1,7 +1,12 @@ import * as React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery } from "@tanstack/react-query"; -import { useForm, type FormState, type UseFormRegister } from "react-hook-form"; +import { + useForm, + useWatch, + type FormState, + type UseFormRegister, +} from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useAuth } from "react-oidc-context"; @@ -84,31 +89,10 @@ export const RatesStage = (props: RatesStageProps) => { }, [rate]), }); - React.useEffect(() => { - if (rate) { - form.reset(rate); - } - }, [form, rate, rate?.rateName, rateName]); - - const isDayRate = React.useMemo( - () => form.watch("isDayRate"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("isDayRate")] - ); - const isWeekDayRate = React.useMemo( - () => form.watch("isDayWeek"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("isDayWeek")] - ); + const isDayRate = useWatch({ control: form.control, name: "isDayRate" }); + const isWeekDayRate = useWatch({ control: form.control, name: "isDayWeek" }); + const totalDays = useWatch({ control: form.control, name: "totalDays" }); - const totalDays = React.useMemo( - () => form.watch("totalDays"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("totalDays")] - ); const rentalDays = totalDays ?? 0; const commonFormProps: CommonRatesFormProps = { @@ -116,6 +100,12 @@ export const RatesStage = (props: RatesStageProps) => { formState: form.formState, }; + React.useEffect(() => { + if (rate) { + form.reset(rate); + } + }, [form, rate, rate?.rateName, rateName]); + return ( {!isSupportingInfoAvailable && ( diff --git a/src/components/add-rental/rental-information/duration-stage.tsx b/src/components/add-rental/rental-information/duration-stage.tsx index 74300941..875e47fe 100644 --- a/src/components/add-rental/rental-information/duration-stage.tsx +++ b/src/components/add-rental/rental-information/duration-stage.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery } from "@tanstack/react-query"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useAuth } from "react-oidc-context"; import { z } from "zod"; @@ -139,7 +139,10 @@ export const DurationStage = ({ ); const agreementTypesList = agreementTypeData.data ?? []; - const currentAgreementType = form.watch("agreementType"); + const currentAgreementType = useWatch({ + control: form.control, + name: "agreementType", + }); const agreementNumberQuery = useQuery( fetchAgreementGeneratedNumberOptions({ auth: authParams, @@ -148,18 +151,14 @@ export const DurationStage = ({ }) ); - const form_checkoutDate = React.useMemo( - () => form.watch("checkoutDate"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("checkoutDate")] - ); - const form_checkinDate = React.useMemo( - () => form.watch("checkinDate"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("checkinDate")] - ); + const form_checkoutDate = useWatch({ + control: form.control, + name: "checkoutDate", + }); + const form_checkinDate = useWatch({ + control: form.control, + name: "checkinDate", + }); const handleCheckoutDateChange = (date: Date) => { const previousCheckoutDate = form_checkoutDate; diff --git a/src/components/add-rental/rental-information/vehicle-stage.tsx b/src/components/add-rental/rental-information/vehicle-stage.tsx index 0be86d88..d52edf74 100644 --- a/src/components/add-rental/rental-information/vehicle-stage.tsx +++ b/src/components/add-rental/rental-information/vehicle-stage.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery } from "@tanstack/react-query"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useAuth } from "react-oidc-context"; import { z } from "zod"; @@ -92,18 +92,11 @@ export const VehicleStage = ({ values: vehicleInformation ? values : undefined, }); - const formVehicleTypeId = React.useMemo( - () => form.watch("vehicleTypeId"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("vehicleTypeId")] - ); - const formVehicleId = React.useMemo( - () => form.watch("vehicleId"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("vehicleId")] - ); + const formVehicleTypeId = useWatch({ + control: form.control, + name: "vehicleTypeId", + }); + const formVehicleId = useWatch({ control: form.control, name: "vehicleId" }); // const vehicleTypesData = useQuery( diff --git a/src/routes/_auth/(dashboard)/-components/widget-grid/widgets/quick-lookup.tsx b/src/routes/_auth/(dashboard)/-components/widget-grid/widgets/quick-lookup.tsx index 061578bc..e587089f 100644 --- a/src/routes/_auth/(dashboard)/-components/widget-grid/widgets/quick-lookup.tsx +++ b/src/routes/_auth/(dashboard)/-components/widget-grid/widgets/quick-lookup.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "@tanstack/react-router"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { z } from "zod"; @@ -90,12 +90,7 @@ export default function SalesStatusWidget(props: CommonWidgetProps) { shouldUnregister: true, }); - const accessor = React.useMemo( - () => form.watch("accessor"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("accessor")] - ); + const accessor = useWatch({ control: form.control, name: "accessor" }); const customers = useMutation({ mutationFn: fetchCustomersSearchListFn, diff --git a/src/routes/_auth/(settings)/-components/application/location-edit-dialog.tsx b/src/routes/_auth/(settings)/-components/application/location-edit-dialog.tsx index 53352944..132553f8 100644 --- a/src/routes/_auth/(settings)/-components/application/location-edit-dialog.tsx +++ b/src/routes/_auth/(settings)/-components/application/location-edit-dialog.tsx @@ -1,7 +1,7 @@ import React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; @@ -346,12 +346,7 @@ function LocationForm(props: LocationFormProps) { }, }); - const countryId = React.useMemo( - () => form.watch("countryId"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("countryId")] - ); + const countryId = useWatch({ control: form.control, name: "countryId" }); const locationsQuery = useQuery( fetchLocationsListOptions({ diff --git a/src/routes/_auth/(settings)/-components/application/role-edit-dialog.tsx b/src/routes/_auth/(settings)/-components/application/role-edit-dialog.tsx index 1cb02d84..8c170855 100644 --- a/src/routes/_auth/(settings)/-components/application/role-edit-dialog.tsx +++ b/src/routes/_auth/(settings)/-components/application/role-edit-dialog.tsx @@ -2,7 +2,7 @@ import React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { AccordionItem } from "@radix-ui/react-accordion"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { z } from "zod"; @@ -375,12 +375,7 @@ function RoleForm(props: { }, }); - const templateId = React.useMemo( - () => form.watch("templateId"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("templateId")] - ); + const templateId = useWatch({ control: form.control, name: "templateId" }); const roleQuery = useQuery( fetchRoleByIdOptions({ diff --git a/src/routes/_auth/(settings)/settings.profile.tsx b/src/routes/_auth/(settings)/settings.profile.tsx index 2c2c6412..ec0b622d 100644 --- a/src/routes/_auth/(settings)/settings.profile.tsx +++ b/src/routes/_auth/(settings)/settings.profile.tsx @@ -6,7 +6,7 @@ import { useSuspenseQuery, } from "@tanstack/react-query"; import { createFileRoute } from "@tanstack/react-router"; -import { useForm, UseFormReturn } from "react-hook-form"; +import { useForm, useWatch, type UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; @@ -334,12 +334,7 @@ const COPY_TIMEOUT = 1500; function UsernameBlock({ form }: BlockProps) { const { t } = useTranslation(); - const username = React.useMemo( - () => form.watch("userName"), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [form.watch("userName")] - ); + const username = useWatch({ control: form.control, name: "userName" }); const [hidden, setHidden] = React.useState(false); const [_, copy] = useCopyToClipboard();