fix: onSubmit should now behave as expected

* fix: memoize all non-function form props by default

* chore: migrate useStableFormOpts to useMemo

* fix: options passed to useField will not always cause a re-render

* chore: minor code cleanups

* test: add previously failing test to demonstrate fix

* chore: fix linting

* fix: running form.update repeatedly should not wipe form state

* test: add test to validate formapi update behavior

* test: add initial tests for useStableOptions

* chore: remove useStableOpts and useFormCallback
This commit is contained in:
Corbin Crutchley
2023-09-06 19:33:52 -07:00
committed by GitHub
parent 9424ed94f8
commit 6f76feee6b
11 changed files with 171 additions and 60 deletions

View File

@@ -2,9 +2,10 @@ import type { FormState, FormOptions } from '@tanstack/form-core'
import { FormApi, functionalUpdate } from '@tanstack/form-core'
import type { NoInfer } from '@tanstack/react-store'
import { useStore } from '@tanstack/react-store'
import React from 'react'
import React, { type ReactNode, useState } from 'react'
import { type UseField, type FieldComponent, Field, useField } from './useField'
import { formContext } from './formContext'
import { useIsomorphicLayoutEffect } from './utils/useIsomorphicLayoutEffect'
declare module '@tanstack/form-core' {
// eslint-disable-next-line no-shadow
@@ -17,15 +18,13 @@ declare module '@tanstack/form-core' {
) => TSelected
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
children:
| ((state: NoInfer<TSelected>) => React.ReactNode)
| React.ReactNode
children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode
}) => any
}
}
export function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {
const [formApi] = React.useState(() => {
const [formApi] = useState(() => {
// @ts-ignore
const api = new FormApi<TData>(opts)
@@ -58,9 +57,13 @@ export function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {
formApi.useStore((state) => state.isSubmitting)
React.useEffect(() => {
/**
* formApi.update should not have any side effects. Think of it like a `useRef`
* that we need to keep updated every render with the most up-to-date information.
*/
useIsomorphicLayoutEffect(() => {
formApi.update(opts)
}, [formApi, opts])
})
return formApi as any
}