From cfac2ac036459845d68f5a606699b92373f9a50d Mon Sep 17 00:00:00 2001 From: fuko <43729152+fulopkovacs@users.noreply.github.com> Date: Sat, 2 Mar 2024 01:20:40 +0100 Subject: [PATCH 1/4] chore: handle a bug in older versions of TypeScript (<5.1.6) (#611) * Ignore the react-form tests for TypeScript 5.0.4 * Document the JSX-related TS bug in the source code * Add a note about the TS-bugs to the docs --- docs/framework/react/reference/formApi.md | 1 + packages/react-form/package.json | 2 +- packages/react-form/src/useForm.tsx | 11 +++++++++++ packages/react-form/tsconfig.50.json | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 packages/react-form/tsconfig.50.json diff --git a/docs/framework/react/reference/formApi.md b/docs/framework/react/reference/formApi.md index e1d93401d..1a966802c 100644 --- a/docs/framework/react/reference/formApi.md +++ b/docs/framework/react/reference/formApi.md @@ -32,3 +32,4 @@ When using `@tanstack/react-form`, the [core form API](../../reference/formApi) }) => JSX.Element ``` - A `Subscribe` function that allows you to listen and react to changes in the form's state. It's especially useful when you need to execute side effects or render specific components in response to state updates. + > Note that TypeScript `5.0.4` and older versions will incorrectly complain if the `selector` method doesn't return the form's full state (`state`). This is caused by a [bug in TypeScript](https://github.com/TanStack/form/pull/606#discussion_r1506715714), and you can safely ignore it with `//@ts-expect-error` directive. diff --git a/packages/react-form/package.json b/packages/react-form/package.json index 51037d277..3bfaa11ae 100644 --- a/packages/react-form/package.json +++ b/packages/react-form/package.json @@ -15,7 +15,7 @@ "clean": "rimraf ./dist && rimraf ./coverage", "test:eslint": "eslint --ext .ts,.tsx ./src", "test:types:versions49": "node ../../node_modules/typescript49/lib/tsc.js --project tsconfig.legacy.json", - "test:types:versions50": "node ../../node_modules/typescript50/lib/tsc.js", + "test:types:versions50": "node ../../node_modules/typescript50/lib/tsc.js --project tsconfig.50.json", "test:types:versions51": "node ../../node_modules/typescript51/lib/tsc.js", "test:types:versions52": "tsc", "test:types": "pnpm run \"/^test:types:versions.*/\"", diff --git a/packages/react-form/src/useForm.tsx b/packages/react-form/src/useForm.tsx index e69d72db2..a79d24ca7 100644 --- a/packages/react-form/src/useForm.tsx +++ b/packages/react-form/src/useForm.tsx @@ -22,6 +22,17 @@ declare module '@tanstack/form-core' { selector?: (state: NoInfer>) => TSelected, ) => TSelected Subscribe: >>(props: { + /** + TypeScript versions <=5.0.4 have a bug that prevents + the type of the `TSelected` generic from being inferred + from the return type of this method. + + In these versions, `TSelected` will fall back to the default + type (or `unknown` if that's not defined). + + @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details} + @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`} + */ selector?: (state: NoInfer>) => TSelected children: ((state: NoInfer) => ReactNode) | ReactNode }) => JSX.Element diff --git a/packages/react-form/tsconfig.50.json b/packages/react-form/tsconfig.50.json new file mode 100644 index 000000000..7eb52de1e --- /dev/null +++ b/packages/react-form/tsconfig.50.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/tests/**"] +} From b0ab0b4e8a2c9432bc794330b7ee635f006d84eb Mon Sep 17 00:00:00 2001 From: Mehdi <43219077+Snaylaker@users.noreply.github.com> Date: Mon, 4 Mar 2024 10:03:53 +0100 Subject: [PATCH 2/4] Update ssr.md (#616) --- docs/framework/react/guides/ssr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/framework/react/guides/ssr.md b/docs/framework/react/guides/ssr.md index 14737e651..5b1006df4 100644 --- a/docs/framework/react/guides/ssr.md +++ b/docs/framework/react/guides/ssr.md @@ -76,7 +76,7 @@ export default async function someAction(prev: unknown, formData: FormData) { return await formFactory.validateFormData(formData); } ``` -- The action we've discussed is straightforward yet essential. It activates exclusively on the server side when we submit our form. In the example given, the action employs `formFactory.validateFormData(formData)`. This function takes care of validating the data received from the client during form submission. It's ab efficient way to ensure data compliance with our predefined server rules. +- The action we've discussed is straightforward yet essential. It activates exclusively on the server side when we submit our form. In the example given, the action employs `formFactory.validateFormData(formData)`. This function takes care of validating the data received from the client during form submission. It's an efficient way to ensure data compliance with our predefined server rules. - Now, let's shift our focus to the client component: - For those who might be exploring this for the first time, `useFormState` is a relatively new hook in React. You can find more details in React's documentation on [useFormState](https://react.dev/reference/react-dom/hooks/useFormState). This hook represents a significant advancement as it allows us to dynamically update the state based on the outcomes of a form action. It's an effective way to manage form states, especially in response to server-side interactions. From 96021135df8a54af2f7a830768a314fd38f3dd0a Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Mon, 4 Mar 2024 15:10:29 -0800 Subject: [PATCH 3/4] fix: React StrictMode should no longer crash * fix: react strict mode should no longer crash Fixes #571 * docs: remove old apis from docs * chore: return previous instance instead of generating a new one in React adapter * chore: fix issue with `mount` running twice * test: add test for this edgecase * chore: migrate implementation of useIsomorphicEffectOnce * chore: add name property to useForm * Revert "chore: add name property to useForm" This reverts commit a0b5ea7e58a5dea3863bc5d149d3a752e9213f79. * chore: refactor internals to be more React-y * docs: add a minor docs mention in our debugging guide * chore: apply suggestion from fulopkovacs --- docs/config.json | 5 +- docs/framework/react/guides/debugging.md | 17 ++ docs/reference/fieldApi.md | 4 - docs/reference/formApi.md | 43 ++--- packages/form-core/src/FieldApi.ts | 17 +- packages/form-core/src/FormApi.ts | 40 ++-- packages/form-core/src/tests/FieldApi.spec.ts | 6 +- .../react-form/src/tests/useField.test.tsx | 171 +++++++++++++++++- .../react-form/src/tests/useForm.test.tsx | 24 +++ packages/react-form/src/useField.tsx | 18 +- packages/react-form/src/useForm.tsx | 1 - .../react-form/src/useIsomorphicEffectOnce.ts | 39 ---- 12 files changed, 252 insertions(+), 133 deletions(-) create mode 100644 docs/framework/react/guides/debugging.md delete mode 100644 packages/react-form/src/useIsomorphicEffectOnce.ts diff --git a/docs/config.json b/docs/config.json index ea14d4fd6..eaf6aec8b 100644 --- a/docs/config.json +++ b/docs/config.json @@ -85,7 +85,10 @@ { "label": "SSR/Next.js", "to": "framework/react/guides/ssr" - + }, + { + "label": "Debugging", + "to": "framework/react/guides/debugging" } ] }, diff --git a/docs/framework/react/guides/debugging.md b/docs/framework/react/guides/debugging.md new file mode 100644 index 000000000..305b2f35e --- /dev/null +++ b/docs/framework/react/guides/debugging.md @@ -0,0 +1,17 @@ +--- +id: debugging +title: Debugging React Usage +--- + +Here's a list of common errors you might see in the console and how to fix them. + +# Changing an uncontrolled input to be controlled + +If you see this error in the console: + +``` +Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components +``` + +It's likely you forgot the `defaultValues` in your `useForm` Hook or `form.Field` component usage. This is occurring +because the input is being rendered before the form value is initialized and is therefore changing from `undefined` to `""` when a text input is made. diff --git a/docs/reference/fieldApi.md b/docs/reference/fieldApi.md index 50623ce06..e601b9343 100644 --- a/docs/reference/fieldApi.md +++ b/docs/reference/fieldApi.md @@ -164,10 +164,6 @@ A class representing the API for managing a form field. #### Properties -- ```tsx - uid: number - ``` - - A unique identifier for the field instance. - ```tsx form: FormApi ``` diff --git a/docs/reference/formApi.md b/docs/reference/formApi.md index 3b71c867c..e79ed610a 100644 --- a/docs/reference/formApi.md +++ b/docs/reference/formApi.md @@ -29,7 +29,7 @@ An object representing the options for a form. defaultValues?: TData ``` - Set initial values for your form. - + - ```tsx defaultState?: Partial> ``` @@ -61,7 +61,7 @@ An object representing the options for a form. onMount?: (values: TData, formApi: FormApi) => ValidationError ``` - Optional function that fires as soon as the component mounts. - + - ```tsx onChange?: (values: TData, formApi: FormApi) => ValidationError ``` @@ -102,17 +102,17 @@ A class representing the Form API. It handles the logic and interactions with th options: FormOptions = {} ``` - The options for the form. - + - ```tsx store: Store> ``` - A [TanStack Store instance](https://tanstack.com/store/latest/docs/reference/Store) that keeps track of the form's state. - + - ```tsx state: FormState ``` - The current state of the form. - + - ```tsx fieldInfo: Record, FieldInfo> = {} as any @@ -197,62 +197,62 @@ An object representing the current state of the form. errorMap: ValidationErrorMap ``` - The error map for the form itself. - + - ```tsx isFormValidating: boolean ``` - A boolean indicating if the form is currently validating. - + - ```tsx isFormValid: boolean ``` - A boolean indicating if the form is valid. - + - ```tsx fieldMeta: Record, FieldMeta> ``` - A record of field metadata for each field in the form. - + - ```tsx isFieldsValidating: boolean ``` - A boolean indicating if any of the form fields are currently validating. - + - ```tsx isFieldsValid: boolean ``` - A boolean indicating if all the form fields are valid. - + - ```tsx isSubmitting: boolean ``` - A boolean indicating if the form is currently submitting. - + - ```tsx isTouched: boolean ``` - A boolean indicating if any of the form fields have been touched. - + - ```tsx isSubmitted: boolean ``` - A boolean indicating if the form has been submitted. - + - ```tsx isValidating: boolean ``` - A boolean indicating if the form or any of its fields are currently validating. - + - ```tsx isValid: boolean ``` - A boolean indicating if the form and all its fields are valid. - + - ```tsx canSubmit: boolean ``` - A boolean indicating if the form can be submitted based on its current state. - + - ```tsx submissionAttempts: number ``` @@ -268,17 +268,14 @@ An object representing the current state of the form. An object representing the field information for a specific field within the form. - ```tsx - instances: Record< - string, - FieldApi< + instance: FieldApi< TFormData, any, Validator | undefined, TFormValidator - > - > + > | null ``` - - A record of field instances with unique identifiers as keys. + - An instance of the `FieldAPI`. - ```tsx validationMetaMap: Record diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts index 4b92d62a7..e977e9319 100644 --- a/packages/form-core/src/FieldApi.ts +++ b/packages/form-core/src/FieldApi.ts @@ -237,8 +237,6 @@ export type FieldMeta = { isValidating: boolean } -let uid = 0 - export type FieldState = { value: TData meta: FieldMeta @@ -259,7 +257,6 @@ export class FieldApi< | undefined = undefined, TData extends DeepValue = DeepValue, > { - uid: number form: FieldApiOptions< TParentData, TName, @@ -289,13 +286,6 @@ export class FieldApi< >, ) { this.form = opts.form as never - this.uid = uid++ - // Support field prefixing from FieldScope - // let fieldPrefix = '' - // if (this.form.fieldName) { - // fieldPrefix = `${this.form.fieldName}.` - // } - this.name = opts.name as never if (opts.defaultValue !== undefined) { @@ -362,7 +352,7 @@ export class FieldApi< mount = () => { const info = this.getInfo() - info.instances[this.uid] = this as never + info.instance = this as never const unsubscribe = this.form.store.subscribe(() => { this.store.batch(() => { const nextValue = this.getValue() @@ -403,13 +393,8 @@ export class FieldApi< const preserveValue = this.options.preserveValue unsubscribe() if (!preserveValue) { - delete info.instances[this.uid] this.form.deleteField(this.name) } - - if (!Object.keys(info.instances).length && !preserveValue) { - delete this.form.fieldInfo[this.name] - } } } diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index ae5cfab4b..abc3f8bce 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -104,15 +104,12 @@ export type FieldInfo< TFormData, TFormValidator extends Validator | undefined = undefined, > = { - instances: Record< - string, - FieldApi< - TFormData, - any, - Validator | undefined, - TFormValidator - > - > + instance: FieldApi< + TFormData, + any, + Validator | undefined, + TFormValidator + > | null validationMetaMap: Record } @@ -340,17 +337,17 @@ export class FormApi< void ( Object.values(this.fieldInfo) as FieldInfo[] ).forEach((field) => { - Object.values(field.instances).forEach((instance) => { - // Validate the field - fieldValidationPromises.push( - Promise.resolve().then(() => instance.validate(cause)), - ) - // If any fields are not touched - if (!instance.state.meta.isTouched) { - // Mark them as touched - instance.setMeta((prev) => ({ ...prev, isTouched: true })) - } - }) + if (!field.instance) return + const fieldInstance = field.instance + // Validate the field + fieldValidationPromises.push( + Promise.resolve().then(() => fieldInstance.validate(cause)), + ) + // If any fields are not touched + if (!field.instance.state.meta.isTouched) { + // Mark them as touched + field.instance.setMeta((prev) => ({ ...prev, isTouched: true })) + } }) }) @@ -587,7 +584,7 @@ export class FormApi< ): FieldInfo => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition return (this.fieldInfo[field] ||= { - instances: {}, + instance: null, validationMetaMap: { onChange: undefined, onBlur: undefined, @@ -645,6 +642,7 @@ export class FormApi< return newState }) + delete this.fieldInfo[field] } pushFieldValue = >( diff --git a/packages/form-core/src/tests/FieldApi.spec.ts b/packages/form-core/src/tests/FieldApi.spec.ts index 2e1106de8..cf0b54e12 100644 --- a/packages/form-core/src/tests/FieldApi.spec.ts +++ b/packages/form-core/src/tests/FieldApi.spec.ts @@ -602,7 +602,7 @@ describe('field api', () => { const unmount = field.mount() unmount() - expect(form.getFieldInfo(field.name).instances[field.uid]).toBeDefined() + expect(form.getFieldInfo(field.name).instance).toBeDefined() expect(form.getFieldInfo(field.name)).toBeDefined() }) @@ -624,8 +624,8 @@ describe('field api', () => { unmount() const info = form.getFieldInfo(field.name) subscription() - expect(info.instances[field.uid]).toBeUndefined() - expect(Object.keys(info.instances).length).toBe(0) + expect(info.instance).toBeNull() + expect(Object.keys(info.instance ?? {}).length).toBe(0) // Check that form store has been updated expect(callback).toHaveBeenCalledOnce() diff --git a/packages/react-form/src/tests/useField.test.tsx b/packages/react-form/src/tests/useField.test.tsx index a8e4e9f69..24b805c03 100644 --- a/packages/react-form/src/tests/useField.test.tsx +++ b/packages/react-form/src/tests/useField.test.tsx @@ -3,9 +3,9 @@ import * as React from 'react' import { render, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import '@testing-library/jest-dom' -import { createFormFactory } from '../index' +import { createFormFactory, useForm } from '../index' import { sleep } from './utils' -import type { FormApi } from '../index' +import type { FieldApi, FormApi } from '../index' const user = userEvent.setup() @@ -101,7 +101,12 @@ describe('useField', () => { const formFactory = createFormFactory() function Comp() { - const form = formFactory.useForm() + const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( @@ -143,7 +148,12 @@ describe('useField', () => { const formFactory = createFormFactory() function Comp() { - const form = formFactory.useForm() + const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( @@ -188,7 +198,12 @@ describe('useField', () => { const formFactory = createFormFactory() function Comp() { - const form = formFactory.useForm() + const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( @@ -239,7 +254,12 @@ describe('useField', () => { const formFactory = createFormFactory() function Comp() { - const form = formFactory.useForm() + const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( @@ -288,7 +308,12 @@ describe('useField', () => { const formFactory = createFormFactory() function Comp() { - const form = formFactory.useForm() + const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( @@ -346,7 +371,12 @@ describe('useField', () => { const formFactory = createFormFactory() function Comp() { - const form = formFactory.useForm() + const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( @@ -395,7 +425,12 @@ describe('useField', () => { const formFactory = createFormFactory() let form: FormApi | null = null function Comp() { - form = formFactory.useForm() + form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( { const formFactory = createFormFactory() let form: FormApi | null = null function Comp() { - form = formFactory.useForm() + form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + }) return ( { const info = form!.fieldInfo expect(Object.keys(info)).toHaveLength(0) }) + + it('should handle strict mode properly with conditional fields', async () => { + function FieldInfo({ field }: { field: FieldApi }) { + return ( + <> + {field.state.meta.touchedErrors ? ( + {field.state.meta.touchedErrors} + ) : null} + {field.state.meta.isValidating ? 'Validating...' : null} + + ) + } + + function Comp() { + const [showField, setShowField] = React.useState(true) + + const form = useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + // eslint-disable-next-line @typescript-eslint/no-empty-function + onSubmit: async () => {}, + }) + + return ( +
+ +
{ + e.preventDefault() + e.stopPropagation() + void form.handleSubmit() + }} + > +
+ {/* A type-safe field component*/} + {showField ? ( + + !value ? 'A first name is required' : undefined, + }} + children={(field) => { + // Avoid hasty abstractions. Render props are great! + return ( + <> + + field.handleChange(e.target.value)} + /> + + + ) + }} + /> + ) : null} +
+
+ ( + <> + + field.handleChange(e.target.value)} + /> + + + )} + /> +
+ [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> + + +
+
+ ) + } + + const { getByText, findByText, queryByText } = render( + + + , + ) + + await user.click(getByText('Submit')) + expect(await findByText('A first name is required')).toBeInTheDocument() + await user.click(getByText('Hide field')) + await user.click(getByText('Submit')) + expect(queryByText('A first name is required')).not.toBeInTheDocument() + }) }) diff --git a/packages/react-form/src/tests/useForm.test.tsx b/packages/react-form/src/tests/useForm.test.tsx index 34d1d4f23..fc5b67629 100644 --- a/packages/react-form/src/tests/useForm.test.tsx +++ b/packages/react-form/src/tests/useForm.test.tsx @@ -172,6 +172,10 @@ describe('useForm', () => { function Comp() { const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, validators: { onChange() { return error @@ -217,6 +221,10 @@ describe('useForm', () => { function Comp() { const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, validators: { onChange: ({ value }) => value.firstName === 'other' ? error : undefined, @@ -262,6 +270,10 @@ describe('useForm', () => { function Comp() { const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, validators: { onChange: ({ value }) => value.firstName === 'other' ? error : undefined, @@ -362,6 +374,10 @@ describe('useForm', () => { function Comp() { const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, validators: { onChangeAsync: async () => { await sleep(10) @@ -412,6 +428,10 @@ describe('useForm', () => { function Comp() { const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, validators: { onChangeAsync: async () => { await sleep(10) @@ -472,6 +492,10 @@ describe('useForm', () => { function Comp() { const form = formFactory.useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, validators: { onChangeAsyncDebounceMs: 100, onChangeAsync: async () => { diff --git a/packages/react-form/src/useField.tsx b/packages/react-form/src/useField.tsx index 299d6c06b..afebf4a0d 100644 --- a/packages/react-form/src/useField.tsx +++ b/packages/react-form/src/useField.tsx @@ -1,9 +1,8 @@ -import React, { useRef, useState } from 'rehackt' +import React, { useState } from 'rehackt' import { useStore } from '@tanstack/react-store' import { FieldApi, functionalUpdate } from '@tanstack/form-core' import { formContext, useFormContext } from './formContext' import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect' -import { useIsomorphicEffectOnce } from './useIsomorphicEffectOnce' import type { UseFieldOptions } from './types' import type { DeepKeys, @@ -88,6 +87,8 @@ export function useField< return api }) + useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi]) + /** * fieldApi.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. @@ -104,19 +105,6 @@ export function useField< } : undefined, ) - const unmountFn = useRef<(() => void) | null>(null) - - useIsomorphicEffectOnce(() => { - return () => { - unmountFn.current?.() - } - }) - - // We have to mount it right as soon as it renders, otherwise we get: - // https://github.com/TanStack/form/issues/523 - if (!unmountFn.current) { - unmountFn.current = fieldApi.mount() - } return fieldApi as never } diff --git a/packages/react-form/src/useForm.tsx b/packages/react-form/src/useForm.tsx index a79d24ca7..61745a1cc 100644 --- a/packages/react-form/src/useForm.tsx +++ b/packages/react-form/src/useForm.tsx @@ -46,7 +46,6 @@ export function useForm< opts?: FormOptions, ): FormApi { const [formApi] = useState(() => { - // @ts-ignore const api = new FormApi(opts) api.Provider = function Provider(props) { diff --git a/packages/react-form/src/useIsomorphicEffectOnce.ts b/packages/react-form/src/useIsomorphicEffectOnce.ts deleted file mode 100644 index ee0fc972a..000000000 --- a/packages/react-form/src/useIsomorphicEffectOnce.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useRef, useState } from 'rehackt' -import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect' -import type { EffectCallback } from 'rehackt' - -/** - * This hook handles StrictMode and prod mode - */ -export const useIsomorphicEffectOnce = (effect: EffectCallback) => { - const destroyFunc = useRef void)>() - const effectCalled = useRef(false) - const renderAfterCalled = useRef(false) - const [val, setVal] = useState(0) - - if (effectCalled.current) { - renderAfterCalled.current = true - } - - useIsomorphicLayoutEffect(() => { - // only execute the effect first time around - if (!effectCalled.current) { - destroyFunc.current = effect() - effectCalled.current = true - } - - // this forces one render after the effect is run - setVal((v) => v + 1) - - return () => { - // if the comp didn't render since the useEffect was called, - // we know it's the dummy React cycle - if (!renderAfterCalled.current) { - return - } - if (destroyFunc.current) { - destroyFunc.current() - } - } - }, []) -} From a6518469972a0052b3d1ffb716bd2d4892f0ce06 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Mon, 4 Mar 2024 23:11:53 +0000 Subject: [PATCH 4/4] release: v0.13.7 --- .../react/next-server-actions/package.json | 2 +- examples/react/simple/package.json | 2 +- examples/react/ui-libraries/package.json | 2 +- examples/react/valibot/package.json | 4 +- examples/react/yup/package.json | 4 +- examples/react/zod/package.json | 4 +- examples/solid/simple/package.json | 2 +- examples/solid/valibot/package.json | 4 +- examples/solid/yup/package.json | 4 +- examples/solid/zod/package.json | 4 +- examples/vue/simple/package.json | 2 +- examples/vue/valibot/package.json | 4 +- examples/vue/yup/package.json | 4 +- examples/vue/zod/package.json | 4 +- packages/form-core/package.json | 2 +- packages/react-form/package.json | 2 +- packages/solid-form/package.json | 2 +- packages/valibot-form-adapter/package.json | 2 +- packages/vue-form/package.json | 2 +- packages/yup-form-adapter/package.json | 2 +- packages/zod-form-adapter/package.json | 2 +- pnpm-lock.yaml | 46 +++++++++---------- 22 files changed, 53 insertions(+), 53 deletions(-) diff --git a/examples/react/next-server-actions/package.json b/examples/react/next-server-actions/package.json index 656225311..16cbd86f8 100644 --- a/examples/react/next-server-actions/package.json +++ b/examples/react/next-server-actions/package.json @@ -12,7 +12,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "next": "14.0.4", - "@tanstack/react-form": "^0.13.6" + "@tanstack/react-form": "^0.13.7" }, "devDependencies": { "typescript": "5.2.2", diff --git a/examples/react/simple/package.json b/examples/react/simple/package.json index 4f4f32ea4..504a077f0 100644 --- a/examples/react/simple/package.json +++ b/examples/react/simple/package.json @@ -9,7 +9,7 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^0.13.6", + "@tanstack/react-form": "^0.13.7", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/react/ui-libraries/package.json b/examples/react/ui-libraries/package.json index 8f0a7421f..996a48615 100644 --- a/examples/react/ui-libraries/package.json +++ b/examples/react/ui-libraries/package.json @@ -14,7 +14,7 @@ "@mantine/core": "7.3.2", "@mantine/hooks": "7.3.2", "@mui/material": "5.15.2", - "@tanstack/react-form": "^0.13.6", + "@tanstack/react-form": "^0.13.7", "@yme/lay-postcss": "0.1.0", "postcss": "8.4.32", "postcss-preset-mantine": "1.12.2", diff --git a/examples/react/valibot/package.json b/examples/react/valibot/package.json index 0006022aa..d6082f412 100644 --- a/examples/react/valibot/package.json +++ b/examples/react/valibot/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^0.13.6", - "@tanstack/valibot-form-adapter": "^0.13.6", + "@tanstack/react-form": "^0.13.7", + "@tanstack/valibot-form-adapter": "^0.13.7", "react": "^18.2.0", "react-dom": "^18.2.0", "valibot": "^0.20.1" diff --git a/examples/react/yup/package.json b/examples/react/yup/package.json index 9b8cd8566..294ff0408 100644 --- a/examples/react/yup/package.json +++ b/examples/react/yup/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^0.13.6", - "@tanstack/yup-form-adapter": "^0.13.6", + "@tanstack/react-form": "^0.13.7", + "@tanstack/yup-form-adapter": "^0.13.7", "react": "^18.2.0", "react-dom": "^18.2.0", "yup": "^1.3.2" diff --git a/examples/react/zod/package.json b/examples/react/zod/package.json index cf1efa580..92ea4de96 100644 --- a/examples/react/zod/package.json +++ b/examples/react/zod/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-form": "^0.13.6", - "@tanstack/zod-form-adapter": "^0.13.6", + "@tanstack/react-form": "^0.13.7", + "@tanstack/zod-form-adapter": "^0.13.7", "react": "^18.2.0", "react-dom": "^18.2.0", "zod": "^3.22.4" diff --git a/examples/solid/simple/package.json b/examples/solid/simple/package.json index 2a167a32b..cbcbad862 100644 --- a/examples/solid/simple/package.json +++ b/examples/solid/simple/package.json @@ -9,7 +9,7 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/solid-form": "^0.13.6", + "@tanstack/solid-form": "^0.13.7", "solid-js": "^1.7.8" }, "devDependencies": { diff --git a/examples/solid/valibot/package.json b/examples/solid/valibot/package.json index be812c34d..561a463cf 100644 --- a/examples/solid/valibot/package.json +++ b/examples/solid/valibot/package.json @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/solid-form": "^0.13.6", - "@tanstack/valibot-form-adapter": "^0.13.6", + "@tanstack/solid-form": "^0.13.7", + "@tanstack/valibot-form-adapter": "^0.13.7", "solid-js": "^1.7.8", "valibot": "^0.20.1" }, diff --git a/examples/solid/yup/package.json b/examples/solid/yup/package.json index 956300462..014a12079 100644 --- a/examples/solid/yup/package.json +++ b/examples/solid/yup/package.json @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/solid-form": "^0.13.6", - "@tanstack/yup-form-adapter": "^0.13.6", + "@tanstack/solid-form": "^0.13.7", + "@tanstack/yup-form-adapter": "^0.13.7", "solid-js": "^1.7.8", "yup": "^1.3.2" }, diff --git a/examples/solid/zod/package.json b/examples/solid/zod/package.json index e72e8fa8e..889956f25 100644 --- a/examples/solid/zod/package.json +++ b/examples/solid/zod/package.json @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/solid-form": "^0.13.6", - "@tanstack/zod-form-adapter": "^0.13.6", + "@tanstack/solid-form": "^0.13.7", + "@tanstack/zod-form-adapter": "^0.13.7", "solid-js": "^1.7.8", "zod": "^3.22.4" }, diff --git a/examples/vue/simple/package.json b/examples/vue/simple/package.json index 68f783b46..2e0fb2337 100644 --- a/examples/vue/simple/package.json +++ b/examples/vue/simple/package.json @@ -9,7 +9,7 @@ "serve": "vite preview" }, "dependencies": { - "@tanstack/vue-form": "^0.13.6", + "@tanstack/vue-form": "^0.13.7", "vue": "^3.3.4" }, "devDependencies": { diff --git a/examples/vue/valibot/package.json b/examples/vue/valibot/package.json index 9e7778e62..389bbe4e6 100644 --- a/examples/vue/valibot/package.json +++ b/examples/vue/valibot/package.json @@ -9,8 +9,8 @@ "serve": "vite preview" }, "dependencies": { - "@tanstack/vue-form": "^0.13.6", - "@tanstack/valibot-form-adapter": "^0.13.6", + "@tanstack/vue-form": "^0.13.7", + "@tanstack/valibot-form-adapter": "^0.13.7", "vue": "^3.3.4", "valibot": "^0.20.1" }, diff --git a/examples/vue/yup/package.json b/examples/vue/yup/package.json index 51afed7e4..73e4e99d4 100644 --- a/examples/vue/yup/package.json +++ b/examples/vue/yup/package.json @@ -9,8 +9,8 @@ "serve": "vite preview" }, "dependencies": { - "@tanstack/vue-form": "^0.13.6", - "@tanstack/yup-form-adapter": "^0.13.6", + "@tanstack/vue-form": "^0.13.7", + "@tanstack/yup-form-adapter": "^0.13.7", "vue": "^3.3.4", "yup": "^1.3.2" }, diff --git a/examples/vue/zod/package.json b/examples/vue/zod/package.json index 4edefc3f7..805efa4ab 100644 --- a/examples/vue/zod/package.json +++ b/examples/vue/zod/package.json @@ -9,8 +9,8 @@ "serve": "vite preview" }, "dependencies": { - "@tanstack/vue-form": "^0.13.6", - "@tanstack/zod-form-adapter": "^0.13.6", + "@tanstack/vue-form": "^0.13.7", + "@tanstack/zod-form-adapter": "^0.13.7", "vue": "^3.3.4", "zod": "^3.22.4" }, diff --git a/packages/form-core/package.json b/packages/form-core/package.json index 9907401cc..e9eb96847 100644 --- a/packages/form-core/package.json +++ b/packages/form-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/form-core", - "version": "0.13.6", + "version": "0.13.7", "description": "Powerful, type-safe, framework agnostic forms.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/react-form/package.json b/packages/react-form/package.json index 3bfaa11ae..c79bd3544 100644 --- a/packages/react-form/package.json +++ b/packages/react-form/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-form", - "version": "0.13.6", + "version": "0.13.7", "description": "Powerful, type-safe forms for React.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/solid-form/package.json b/packages/solid-form/package.json index acf23cc51..c029df2ca 100644 --- a/packages/solid-form/package.json +++ b/packages/solid-form/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-form", - "version": "0.13.6", + "version": "0.13.7", "description": "Powerful, type-safe forms for Solid.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/valibot-form-adapter/package.json b/packages/valibot-form-adapter/package.json index 3ec3c6daa..15e0acdbd 100644 --- a/packages/valibot-form-adapter/package.json +++ b/packages/valibot-form-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/valibot-form-adapter", - "version": "0.13.6", + "version": "0.13.7", "description": "The Valibot adapter for TanStack Form.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/vue-form/package.json b/packages/vue-form/package.json index 1116ffea2..4e7a7ccde 100644 --- a/packages/vue-form/package.json +++ b/packages/vue-form/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/vue-form", - "version": "0.13.6", + "version": "0.13.7", "description": "Powerful, type-safe forms for Vue.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/yup-form-adapter/package.json b/packages/yup-form-adapter/package.json index 54d682c94..2541fdea3 100644 --- a/packages/yup-form-adapter/package.json +++ b/packages/yup-form-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/yup-form-adapter", - "version": "0.13.6", + "version": "0.13.7", "description": "The Yup adapter for TanStack Form.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/zod-form-adapter/package.json b/packages/zod-form-adapter/package.json index d7a05f1eb..2a0f91ce1 100644 --- a/packages/zod-form-adapter/package.json +++ b/packages/zod-form-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/zod-form-adapter", - "version": "0.13.6", + "version": "0.13.7", "description": "The Zod adapter for TanStack Form.", "author": "tannerlinsley", "license": "MIT", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8da403ba3..da65159a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -123,7 +123,7 @@ importers: examples/react/next-server-actions: dependencies: '@tanstack/react-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/react-form next: specifier: 14.0.4 @@ -157,7 +157,7 @@ importers: examples/react/simple: dependencies: '@tanstack/react-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/react-form react: specifier: ^18.2.0 @@ -191,7 +191,7 @@ importers: specifier: 5.15.2 version: 5.15.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@tanstack/react-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/react-form '@yme/lay-postcss': specifier: 0.1.0 @@ -252,10 +252,10 @@ importers: examples/react/valibot: dependencies: '@tanstack/react-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/react-form '@tanstack/valibot-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/valibot-form-adapter react: specifier: ^18.2.0 @@ -277,10 +277,10 @@ importers: examples/react/yup: dependencies: '@tanstack/react-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/react-form '@tanstack/yup-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/yup-form-adapter react: specifier: ^18.2.0 @@ -302,10 +302,10 @@ importers: examples/react/zod: dependencies: '@tanstack/react-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/react-form '@tanstack/zod-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/zod-form-adapter react: specifier: ^18.2.0 @@ -327,7 +327,7 @@ importers: examples/solid/simple: dependencies: '@tanstack/solid-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/solid-form solid-js: specifier: ^1.7.8 @@ -346,10 +346,10 @@ importers: examples/solid/valibot: dependencies: '@tanstack/solid-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/solid-form '@tanstack/valibot-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/valibot-form-adapter solid-js: specifier: ^1.7.8 @@ -371,10 +371,10 @@ importers: examples/solid/yup: dependencies: '@tanstack/solid-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/solid-form '@tanstack/yup-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/yup-form-adapter solid-js: specifier: ^1.7.8 @@ -396,10 +396,10 @@ importers: examples/solid/zod: dependencies: '@tanstack/solid-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/solid-form '@tanstack/zod-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/zod-form-adapter solid-js: specifier: ^1.7.8 @@ -421,7 +421,7 @@ importers: examples/vue/simple: dependencies: '@tanstack/vue-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/vue-form vue: specifier: ^3.3.4 @@ -443,10 +443,10 @@ importers: examples/vue/valibot: dependencies: '@tanstack/valibot-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/valibot-form-adapter '@tanstack/vue-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/vue-form valibot: specifier: ^0.20.1 @@ -471,10 +471,10 @@ importers: examples/vue/yup: dependencies: '@tanstack/vue-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/vue-form '@tanstack/yup-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/yup-form-adapter vue: specifier: ^3.3.4 @@ -499,10 +499,10 @@ importers: examples/vue/zod: dependencies: '@tanstack/vue-form': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/vue-form '@tanstack/zod-form-adapter': - specifier: ^0.13.6 + specifier: ^0.13.7 version: link:../../../packages/zod-form-adapter vue: specifier: ^3.3.4