Skip to content

Commit

Permalink
refactor: use the useWatch from react-hook-form to get around the r…
Browse files Browse the repository at this point in the history
…eact-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.
  • Loading branch information
SeanCassiere authored Jun 22, 2024
1 parent 5f737ce commit 021e149
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 87 deletions.
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -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 (
<Form {...form}>
Expand Down
40 changes: 15 additions & 25 deletions src/components/add-rental/rates-and-charges/rates-stage.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -84,38 +89,23 @@ 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 = {
registerFn: form.register,
formState: form.formState,
};

React.useEffect(() => {
if (rate) {
form.reset(rate);
}
}, [form, rate, rate?.rateName, rateName]);

return (
<Form {...form}>
{!isSupportingInfoAvailable && (
Expand Down
27 changes: 13 additions & 14 deletions src/components/add-rental/rental-information/duration-stage.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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,
Expand All @@ -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;
Expand Down
19 changes: 6 additions & 13 deletions src/components/add-rental/rental-information/vehicle-stage.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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({
Expand Down
9 changes: 2 additions & 7 deletions src/routes/_auth/(settings)/settings.profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 021e149

Please sign in to comment.