diff --git a/.changeset/witty-chefs-greet.md b/.changeset/witty-chefs-greet.md new file mode 100644 index 000000000..7524b189e --- /dev/null +++ b/.changeset/witty-chefs-greet.md @@ -0,0 +1,5 @@ +--- +'@tanstack/react-form': patch +--- + +Remove useId for react 17 user compatibility, replaced with uuid diff --git a/packages/react-form/src/createFormHook.tsx b/packages/react-form/src/createFormHook.tsx index 4413aa999..71a1d7c15 100644 --- a/packages/react-form/src/createFormHook.tsx +++ b/packages/react-form/src/createFormHook.tsx @@ -16,8 +16,8 @@ import type { import type { ComponentType, Context, + FunctionComponent, PropsWithChildren, - ReactNode, } from 'react' import type { FieldComponent } from './useField' import type { ReactFormExtendedApi } from './useForm' @@ -190,7 +190,10 @@ export type AppFieldExtendedReactFormApi< TSubmitMeta, NoInfer > - AppForm: ComponentType + AppForm: ComponentType< + // PropsWithChildren

is not optional in React 17 + PropsWithChildren<{}> + > } export interface WithFormProps< @@ -225,8 +228,8 @@ export interface WithFormProps< > { // Optional, but adds props to the `render` function outside of `form` props?: TRenderProps - render: ( - props: PropsWithChildren< + render: FunctionComponent< + PropsWithChildren< NoInfer & { form: AppFieldExtendedReactFormApi< TFormData, @@ -245,8 +248,8 @@ export interface WithFormProps< TFormComponents > } - >, - ) => ReactNode + > + > } export interface WithFieldGroupProps< @@ -258,8 +261,8 @@ export interface WithFieldGroupProps< > extends BaseFormOptions { // Optional, but adds props to the `render` function outside of `form` props?: TRenderProps - render: ( - props: PropsWithChildren< + render: FunctionComponent< + PropsWithChildren< NoInfer & { group: AppFieldExtendedReactFieldGroupApi< unknown, @@ -282,8 +285,8 @@ export interface WithFieldGroupProps< TFormComponents > } - >, - ) => ReactNode + > + > } export function createFormHook< @@ -341,13 +344,13 @@ export function createFormHook< > { const form = useForm(props) - const AppForm = useMemo(() => { - const AppForm = (({ children }) => { + // PropsWithChildren

is not optional in React 17 + const AppForm = useMemo>>(() => { + return ({ children }) => { return ( {children} ) - }) as ComponentType - return AppForm + } }, [form]) const AppField = useMemo(() => { @@ -520,7 +523,7 @@ export function createFormHook< fields: TFields } >, - ) => ReactNode { + ) => ReturnType { return function Render(innerProps) { const fieldGroupProps = useMemo(() => { return { diff --git a/packages/react-form/src/useField.tsx b/packages/react-form/src/useField.tsx index 61d12c730..0c8d4e3a8 100644 --- a/packages/react-form/src/useField.tsx +++ b/packages/react-form/src/useField.tsx @@ -11,7 +11,7 @@ import type { FormAsyncValidateOrFn, FormValidateOrFn, } from '@tanstack/form-core' -import type { FunctionComponent, ReactNode } from 'react' +import type { FunctionComponent, ReactElement, ReactNode } from 'react' import type { UseFieldOptions, UseFieldOptionsBound } from './types' interface ReactFieldApi< @@ -485,7 +485,7 @@ export type FieldComponent< TFormOnServer, TPatentSubmitMeta, ExtendedApi ->) => ReactNode +>) => ReturnType /** * A type alias representing a field component for a form lens data type. @@ -573,7 +573,7 @@ export type LensFieldComponent< */ onBlurListenTo?: DeepKeys[] } -}) => ReactNode +}) => ReturnType /** * A function component that takes field options and a render function as children and returns a React component. @@ -639,7 +639,7 @@ export const Field = (< TFormOnDynamicAsync, TFormOnServer, TPatentSubmitMeta ->): ReactNode => { +>): ReturnType => { const fieldApi = useField(fieldOptions as any) const jsxToDisplay = useMemo( diff --git a/packages/react-form/src/useFieldGroup.tsx b/packages/react-form/src/useFieldGroup.tsx index d0a00352d..f30432164 100644 --- a/packages/react-form/src/useFieldGroup.tsx +++ b/packages/react-form/src/useFieldGroup.tsx @@ -11,7 +11,12 @@ import type { FormValidateOrFn, } from '@tanstack/form-core' import type { AppFieldExtendedReactFormApi } from './createFormHook' -import type { ComponentType, PropsWithChildren, ReactNode } from 'react' +import type { + ComponentType, + FunctionComponent, + PropsWithChildren, + ReactNode, +} from 'react' import type { LensFieldComponent } from './useField' function LocalSubscribe({ @@ -21,10 +26,10 @@ function LocalSubscribe({ }: PropsWithChildren<{ lens: AnyFieldGroupApi selector: (state: FieldGroupState) => FieldGroupState -}>) { +}>): ReturnType { const data = useStore(lens.store, selector) - return functionalUpdate(children, data) + return <>{functionalUpdate(children, data)} } /** @@ -71,7 +76,7 @@ export type AppFieldExtendedReactFieldGroupApi< TSubmitMeta, NoInfer > - AppForm: ComponentType + AppForm: ComponentType> /** * A React component to render form fields. With this, you can render and manage individual form fields. */ @@ -83,7 +88,7 @@ export type AppFieldExtendedReactFieldGroupApi< Subscribe: >>(props: { selector?: (state: NoInfer>) => TSelected children: ((state: NoInfer) => ReactNode) | ReactNode - }) => ReactNode + }) => ReturnType } export function useFieldGroup< diff --git a/packages/react-form/src/useForm.tsx b/packages/react-form/src/useForm.tsx index 9206b824c..fc24c0a26 100644 --- a/packages/react-form/src/useForm.tsx +++ b/packages/react-form/src/useForm.tsx @@ -1,6 +1,6 @@ -import { FormApi, functionalUpdate } from '@tanstack/form-core' +import { FormApi, functionalUpdate, uuid } from '@tanstack/form-core' import { useStore } from '@tanstack/react-store' -import { useId, useState } from 'react' +import { useMemo, useRef, useState } from 'react' import { Field } from './useField' import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect' import type { @@ -11,7 +11,12 @@ import type { FormState, FormValidateOrFn, } from '@tanstack/form-core' -import type { PropsWithChildren, ReactNode } from 'react' +import type { + FunctionComponent, + PropsWithChildren, + ReactElement, + ReactNode, +} from 'react' import type { FieldComponent } from './useField' import type { NoInfer } from '@tanstack/react-store' @@ -87,7 +92,7 @@ export interface ReactFormApi< >, ) => TSelected children: ((state: NoInfer) => ReactNode) | ReactNode - }) => ReactNode + }) => ReturnType } /** @@ -142,10 +147,10 @@ function LocalSubscribe({ }: PropsWithChildren<{ form: AnyFormApi selector: (state: AnyFormState) => AnyFormState -}>) { +}>): ReturnType { const data = useStore(form.store, selector) - return functionalUpdate(children, data) + return <>{functionalUpdate(children, data)} } /** @@ -182,7 +187,7 @@ export function useForm< TSubmitMeta >, ) { - const formId = useId() + const formId = useRef(opts?.formId ?? uuid()) const [formApi] = useState(() => { const api = new FormApi< @@ -198,7 +203,7 @@ export function useForm< TOnDynamicAsync, TOnServer, TSubmitMeta - >({ ...opts, formId: formId }) + >({ ...opts, formId: formId.current }) const extendedApi: ReactFormExtendedApi< TFormData,