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 6f6e2d06f..1f44b171d 100644 --- a/packages/react-form/src/createFormHook.tsx +++ b/packages/react-form/src/createFormHook.tsx @@ -17,8 +17,8 @@ import type { import type { ComponentType, Context, + FunctionComponent, PropsWithChildren, - ReactNode, } from 'react' import type { FieldComponent } from './useField' import type { ReactFormExtendedApi } from './useForm' @@ -191,7 +191,10 @@ export type AppFieldExtendedReactFormApi< TSubmitMeta, NoInfer > - AppForm: ComponentType + AppForm: ComponentType< + // PropsWithChildren

is not optional in React 17 + PropsWithChildren<{}> + > } export interface WithFormProps< @@ -226,8 +229,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, @@ -246,8 +249,8 @@ export interface WithFormProps< TFormComponents > } - >, - ) => ReactNode + > + > } export interface WithFieldGroupProps< @@ -259,8 +262,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, @@ -283,8 +286,8 @@ export interface WithFieldGroupProps< TFormComponents > } - >, - ) => ReactNode + > + > } export function createFormHook< @@ -342,13 +345,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(() => { @@ -521,7 +524,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 0167e58aa..ced50e2a7 100644 --- a/packages/react-form/src/useField.tsx +++ b/packages/react-form/src/useField.tsx @@ -13,7 +13,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< @@ -496,7 +496,7 @@ export type FieldComponent< TFormOnServer, TPatentSubmitMeta, ExtendedApi ->) => ReactNode +>) => ReturnType /** * A type alias representing a field component for a form lens data type. @@ -584,7 +584,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. @@ -650,7 +650,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 402a17107..063187c52 100644 --- a/packages/react-form/src/useFieldGroup.tsx +++ b/packages/react-form/src/useFieldGroup.tsx @@ -13,7 +13,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({ @@ -23,10 +28,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)} } /** @@ -73,7 +78,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. */ @@ -85,7 +90,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 f9e725974..3246b41a4 100644 --- a/packages/react-form/src/useForm.tsx +++ b/packages/react-form/src/useForm.tsx @@ -1,8 +1,8 @@ 'use client' -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 { useRef, useState } from 'react' import { Field } from './useField' import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect' import type { @@ -13,7 +13,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' @@ -89,7 +94,7 @@ export interface ReactFormApi< >, ) => TSelected children: ((state: NoInfer) => ReactNode) | ReactNode - }) => ReactNode + }) => ReturnType } /** @@ -144,10 +149,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)} } /** @@ -184,7 +189,11 @@ export function useForm< TSubmitMeta >, ) { - const formId = useId() + const formId = useRef(opts?.formId as never) + + if (!formId.current) { + formId.current = uuid() + } const [formApi] = useState(() => { const api = new FormApi< @@ -200,7 +209,7 @@ export function useForm< TOnDynamicAsync, TOnServer, TSubmitMeta - >({ ...opts, formId: formId }) + >({ ...opts, formId: formId.current }) const extendedApi: ReactFormExtendedApi< TFormData,