@@ -1671,7 +1671,7 @@ describe('field api', () => {
16711671
16721672 expect ( form . getFieldValue ( 'lastName' ) ) . toBe ( 'abc' )
16731673 expect ( form . state . fieldMeta . lastName ) . toMatchObject ( {
1674- isTouched : false ,
1674+ isTouched : true ,
16751675 isValid : true ,
16761676 errors : [ ] ,
16771677 } )
@@ -1688,10 +1688,39 @@ describe('field api', () => {
16881688
16891689 remountedLastName . mount ( )
16901690 expect ( remountedLastName . getMeta ( ) . errors ) . toStrictEqual ( [ ] )
1691- expect ( remountedLastName . getMeta ( ) . isTouched ) . toBe ( false )
1691+ expect ( remountedLastName . getMeta ( ) . isTouched ) . toBe ( true )
16921692 expect ( remountedLastName . getValue ( ) ) . toBe ( 'abc' )
16931693 } )
16941694
1695+ it ( 'should preserve field-level defaultValue changes across unmount remount cleanup' , ( ) => {
1696+ const form = new FormApi ( {
1697+ defaultValues : { } as { name ?: string } ,
1698+ cleanupFieldsOnUnmount : true ,
1699+ } )
1700+
1701+ form . mount ( )
1702+
1703+ const field = new FieldApi ( {
1704+ form,
1705+ name : 'name' ,
1706+ defaultValue : 'initial' ,
1707+ } )
1708+
1709+ const unmount = field . mount ( )
1710+ field . setValue ( 'changed' )
1711+ expect ( unmount ) . toBeTypeOf ( 'function' )
1712+ unmount ( )
1713+
1714+ const remountedField = new FieldApi ( {
1715+ form,
1716+ name : 'name' ,
1717+ defaultValue : 'initial' ,
1718+ } )
1719+
1720+ remountedField . mount ( )
1721+ expect ( remountedField . getValue ( ) ) . toBe ( 'changed' )
1722+ } )
1723+
16951724 it ( 'should not apply in-flight async validation results after unmount' , async ( ) => {
16961725 vi . useFakeTimers ( )
16971726
@@ -1732,7 +1761,7 @@ describe('field api', () => {
17321761 await vi . runAllTimersAsync ( )
17331762
17341763 expect ( form . state . fieldMeta . name ) . toMatchObject ( {
1735- isTouched : false ,
1764+ isTouched : true ,
17361765 isValid : true ,
17371766 errors : [ ] ,
17381767 } )
@@ -1812,6 +1841,47 @@ describe('field api', () => {
18121841 expect ( newField . getMeta ( ) . isTouched ) . toBe ( true )
18131842 } )
18141843
1844+ it ( 'should not cancel newer instance async validation when older instance unmounts' , async ( ) => {
1845+ vi . useFakeTimers ( )
1846+
1847+ const form = new FormApi ( {
1848+ defaultValues : {
1849+ name : '' ,
1850+ } ,
1851+ cleanupFieldsOnUnmount : true ,
1852+ } )
1853+
1854+ form . mount ( )
1855+
1856+ const oldField = new FieldApi ( {
1857+ form,
1858+ name : 'name' ,
1859+ } )
1860+ const oldUnmount = oldField . mount ( )
1861+
1862+ const newField = new FieldApi ( {
1863+ form,
1864+ name : 'name' ,
1865+ validators : {
1866+ onChangeAsyncDebounceMs : 10 ,
1867+ onChangeAsync : async ( { value } ) =>
1868+ value === 'taken' ? 'name is taken' : undefined ,
1869+ } ,
1870+ } )
1871+
1872+ newField . mount ( )
1873+ newField . setValue ( 'taken' )
1874+
1875+ expect ( oldUnmount ) . toBeTypeOf ( 'function' )
1876+ oldUnmount ( )
1877+
1878+ await vi . runAllTimersAsync ( )
1879+
1880+ expect ( newField . getMeta ( ) . errors ) . toContain ( 'name is taken' )
1881+
1882+ vi . useRealTimers ( )
1883+ } )
1884+
18151885 it ( 'should show onSubmit errors' , async ( ) => {
18161886 const form = new FormApi ( {
18171887 defaultValues : {
0 commit comments