Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/witty-chefs-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/react-form': patch
---

Remove useId for react 17 user compatibility, replaced with uuid
33 changes: 18 additions & 15 deletions packages/react-form/src/createFormHook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -190,7 +190,10 @@ export type AppFieldExtendedReactFormApi<
TSubmitMeta,
NoInfer<TFieldComponents>
>
AppForm: ComponentType<PropsWithChildren>
AppForm: ComponentType<
// PropsWithChildren<P> is not optional in React 17
PropsWithChildren<{}>
>
}

export interface WithFormProps<
Expand Down Expand Up @@ -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<TRenderProps> & {
form: AppFieldExtendedReactFormApi<
TFormData,
Expand All @@ -245,8 +248,8 @@ export interface WithFormProps<
TFormComponents
>
}
>,
) => ReactNode
>
>
}

export interface WithFieldGroupProps<
Expand All @@ -258,8 +261,8 @@ export interface WithFieldGroupProps<
> extends BaseFormOptions<TFieldGroupData, TSubmitMeta> {
// Optional, but adds props to the `render` function outside of `form`
props?: TRenderProps
render: (
props: PropsWithChildren<
render: FunctionComponent<
PropsWithChildren<
NoInfer<TRenderProps> & {
group: AppFieldExtendedReactFieldGroupApi<
unknown,
Expand All @@ -282,8 +285,8 @@ export interface WithFieldGroupProps<
TFormComponents
>
}
>,
) => ReactNode
>
>
}

export function createFormHook<
Expand Down Expand Up @@ -341,13 +344,13 @@ export function createFormHook<
> {
const form = useForm(props)

const AppForm = useMemo(() => {
const AppForm = (({ children }) => {
// PropsWithChildren<P> is not optional in React 17
const AppForm = useMemo<ComponentType<PropsWithChildren<{}>>>(() => {
return ({ children }) => {
return (
<formContext.Provider value={form}>{children}</formContext.Provider>
)
}) as ComponentType<PropsWithChildren>
return AppForm
}
}, [form])

const AppField = useMemo(() => {
Expand Down Expand Up @@ -520,7 +523,7 @@ export function createFormHook<
fields: TFields
}
>,
) => ReactNode {
) => ReturnType<FunctionComponent> {
return function Render(innerProps) {
const fieldGroupProps = useMemo(() => {
return {
Expand Down
8 changes: 4 additions & 4 deletions packages/react-form/src/useField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down Expand Up @@ -485,7 +485,7 @@ export type FieldComponent<
TFormOnServer,
TPatentSubmitMeta,
ExtendedApi
>) => ReactNode
>) => ReturnType<FunctionComponent>

/**
* A type alias representing a field component for a form lens data type.
Expand Down Expand Up @@ -573,7 +573,7 @@ export type LensFieldComponent<
*/
onBlurListenTo?: DeepKeys<TLensData>[]
}
}) => ReactNode
}) => ReturnType<FunctionComponent>

/**
* A function component that takes field options and a render function as children and returns a React component.
Expand Down Expand Up @@ -639,7 +639,7 @@ export const Field = (<
TFormOnDynamicAsync,
TFormOnServer,
TPatentSubmitMeta
>): ReactNode => {
>): ReturnType<FunctionComponent> => {
const fieldApi = useField(fieldOptions as any)

const jsxToDisplay = useMemo(
Expand Down
15 changes: 10 additions & 5 deletions packages/react-form/src/useFieldGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -21,10 +26,10 @@ function LocalSubscribe({
}: PropsWithChildren<{
lens: AnyFieldGroupApi
selector: (state: FieldGroupState<any>) => FieldGroupState<any>
}>) {
}>): ReturnType<FunctionComponent> {
const data = useStore(lens.store, selector)

return functionalUpdate(children, data)
return <>{functionalUpdate(children, data)}</>
}

/**
Expand Down Expand Up @@ -71,7 +76,7 @@ export type AppFieldExtendedReactFieldGroupApi<
TSubmitMeta,
NoInfer<TFieldComponents>
>
AppForm: ComponentType<PropsWithChildren>
AppForm: ComponentType<PropsWithChildren<{}>>
/**
* A React component to render form fields. With this, you can render and manage individual form fields.
*/
Expand All @@ -83,7 +88,7 @@ export type AppFieldExtendedReactFieldGroupApi<
Subscribe: <TSelected = NoInfer<FieldGroupState<TFieldGroupData>>>(props: {
selector?: (state: NoInfer<FieldGroupState<TFieldGroupData>>) => TSelected
children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode
}) => ReactNode
}) => ReturnType<FunctionComponent>
}

export function useFieldGroup<
Expand Down
21 changes: 13 additions & 8 deletions packages/react-form/src/useForm.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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'

Expand Down Expand Up @@ -87,7 +92,7 @@ export interface ReactFormApi<
>,
) => TSelected
children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode
}) => ReactNode
}) => ReturnType<FunctionComponent>
}

/**
Expand Down Expand Up @@ -142,10 +147,10 @@ function LocalSubscribe({
}: PropsWithChildren<{
form: AnyFormApi
selector: (state: AnyFormState) => AnyFormState
}>) {
}>): ReturnType<FunctionComponent> {
const data = useStore(form.store, selector)

return functionalUpdate(children, data)
return <>{functionalUpdate(children, data)}</>
}

/**
Expand Down Expand Up @@ -182,7 +187,7 @@ export function useForm<
TSubmitMeta
>,
) {
const formId = useId()
const formId = useRef(opts?.formId ?? uuid())

const [formApi] = useState(() => {
const api = new FormApi<
Expand All @@ -198,7 +203,7 @@ export function useForm<
TOnDynamicAsync,
TOnServer,
TSubmitMeta
>({ ...opts, formId: formId })
>({ ...opts, formId: formId.current })

const extendedApi: ReactFormExtendedApi<
TFormData,
Expand Down
Loading