@gaddario98/react-pages
Version:
A powerful, performance-optimized React plugin for creating dynamic web pages with integrated form management, query handling, and content rendering.
92 lines (82 loc) • 2.62 kB
text/typescript
import { useState, useEffect, useMemo, useCallback } from "react";
import { DefaultValues, useForm, FieldValues, Path } from "react-hook-form";
import { useQueryClient, QueryObserver } from "@tanstack/react-query";
import { FormPageProps } from "../types";
import { QueriesArray } from "@gaddario98/react-queries";
export const useFormPage = <F extends FieldValues, Q extends QueriesArray>({
form,
}: {
form?: FormPageProps<F, Q>;
}) => {
const queryClient = useQueryClient();
const [defaultValueQuery, setDefaultValueQuery] = useState<
DefaultValues<F> | undefined
>(form?.defaultValues);
useEffect(() => {
if (!form?.defaultValueQueryKey) {
setDefaultValueQuery(form?.defaultValues);
return;
}
const initialData = queryClient.getQueryData<DefaultValues<F>>(
form.defaultValueQueryKey
);
if (initialData) {
setDefaultValueQuery(initialData);
}
const observer = new QueryObserver<DefaultValues<F>>(queryClient, {
queryKey: form.defaultValueQueryKey,
enabled: true,
notifyOnChangeProps: ["data"],
refetchOnWindowFocus: false,
});
const unsubscribe = observer.subscribe((result) => {
if (result.data !== undefined) {
setDefaultValueQuery(result.data);
}
});
return () => unsubscribe();
}, [form?.defaultValueQueryKey, form?.defaultValues, queryClient]);
const defaultValues = useMemo(
() =>
({
...(defaultValueQuery ?? {}),
...(form?.defaultValueQueryMap?.(defaultValueQuery) ?? {}),
}) as DefaultValues<F>,
[defaultValueQuery, form]
);
const formControl = useForm<F>({
mode: "all",
...(form?.formSettings ?? {}),
defaultValues,
resetOptions: {
keepDirtyValues: true,
keepDefaultValues: false,
...(form?.formSettings?.resetOptions ?? {}),
},
});
// Memoize formControl to avoid unnecessary re-renders
const stableFormControl = useMemo(() => formControl, []);
useEffect(() => {
stableFormControl.reset(defaultValues, {
keepDirtyValues: true,
keepDefaultValues: false,
});
}, [defaultValues, stableFormControl]);
const formValues = stableFormControl.watch();
const setValueAndTrigger = useCallback(
async (
name: Path<F>,
value: any,
options?: Parameters<typeof stableFormControl.setValue>[2]
) => {
stableFormControl.setValue(name, value, options);
await stableFormControl.trigger(name);
},
[stableFormControl]
);
return {
formValues,
formControl: stableFormControl,
setValue: setValueAndTrigger,
};
};