@@ -109,7 +109,38 @@ export function ArrayField<TFieldValues extends FieldValues = FieldValues>({
109
109
? false
110
110
: '' ; // Default for text, address, etc.
111
111
112
+ // Background and rationale:
113
+ // In certain runtime states (e.g., preview remounts, incidental resets, StrictMode double-invocations),
114
+ // an immediate read right after useFieldArray.append(...) can be stale and still reflect the
115
+ // pre-append array. This manifested as a user-visible bug where adding an item (notably value 0)
116
+ // either did nothing or briefly appeared and then disappeared.
117
+ //
118
+ // To make the operation deterministic, we snapshot the array BEFORE calling append and then
119
+ // verify that the length actually increased. If not, we force-set the array using the snapshot
120
+ // plus the new value. This is safe and idempotent because it only runs when the immediate read
121
+ // did not reflect the append; it does not double-append.
122
+ const fieldsBeforeAppend = fields . length ;
123
+ const valuesBeforeAppend = ( formContext . getValues ( name ) as unknown [ ] | undefined ) ?? [ ] ;
124
+
112
125
append ( defaultValue as FieldValues [ typeof name ] ) ;
126
+
127
+ // Verify append actually reflected in form state; if not, force set
128
+ const afterAppendFieldsCount =
129
+ ( formContext . getValues ( name ) as unknown [ ] | undefined ) ?. length ?? fields . length ;
130
+
131
+ // Fallback: if the immediate read did not reflect the append, coerce to
132
+ // "previous snapshot + new value" so the UI consistently renders the new item.
133
+ if ( afterAppendFieldsCount <= fieldsBeforeAppend ) {
134
+ const baseArray = Array . isArray ( valuesBeforeAppend )
135
+ ? ( valuesBeforeAppend as unknown [ ] )
136
+ : ( [ ] as unknown [ ] ) ;
137
+ const coercedArray = [ ...baseArray , defaultValue ] as unknown [ ] ;
138
+
139
+ formContext . setValue ( name as never , coercedArray as never , {
140
+ shouldDirty : true ,
141
+ shouldTouch : true ,
142
+ } ) ;
143
+ }
113
144
} ;
114
145
115
146
// Check if we can add more items
@@ -182,7 +213,7 @@ export function ArrayField<TFieldValues extends FieldValues = FieldValues>({
182
213
fields . map ( ( field , index ) => {
183
214
// Create field configuration for array element
184
215
const elementField : FormFieldType = {
185
- id : ` ${ id } - ${ index } ` , // Internal ID for the element's field
216
+ id : field . id , // Use RHF field.id for stable, unique keys per item
186
217
name : `${ name } .${ index } ` , // RHF name for the element
187
218
label : elementFieldConfig ?. label || '' , // Label for the element's field (can be empty if not desired)
188
219
type : elementType ,
0 commit comments