@@ -14,6 +14,7 @@ import type { FormContextProps } from './FormContext';
14
14
import FormContext from './FormContext' ;
15
15
import { isSimilar } from './utils/valueUtil' ;
16
16
import ListContext from './ListContext' ;
17
+ import BatchUpdate , { BatchTask , type BatchUpdateRef } from './BatchUpdate' ;
17
18
18
19
type BaseFormProps = Omit < React . FormHTMLAttributes < HTMLFormElement > , 'onSubmit' | 'children' > ;
19
20
@@ -70,6 +71,7 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
70
71
setValidateMessages,
71
72
setPreserve,
72
73
destroyForm,
74
+ setBatchUpdate,
73
75
} = ( formInstance as InternalFormInstance ) . getInternalHooks ( HOOK_MARK ) ;
74
76
75
77
// Pass ref with form instance
@@ -118,6 +120,42 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
118
120
mountRef . current = true ;
119
121
}
120
122
123
+ // ======================== Batch Update ========================
124
+ // zombieJ:
125
+ // To avoid Form self re-render,
126
+ // We create a sub component `BatchUpdate` to handle batch update logic.
127
+ // When the call with do not change immediate, we will batch the update
128
+ // and flush it in `useLayoutEffect` for next tick.
129
+
130
+ // Set batch update ref
131
+ const batchUpdateRef = React . useRef < BatchUpdateRef > ( null ) ;
132
+ const batchUpdateTasksRef = React . useRef < [ key : string , fn : VoidFunction ] [ ] > ( [ ] ) ;
133
+
134
+ const tryFlushBatch = ( ) => {
135
+ if ( batchUpdateRef . current ) {
136
+ batchUpdateTasksRef . current . forEach ( ( [ key , fn ] ) => {
137
+ batchUpdateRef . current . batch ( key , fn ) ;
138
+ } ) ;
139
+ batchUpdateTasksRef . current = [ ] ;
140
+ }
141
+ } ;
142
+
143
+ // Ref update
144
+ const setBatchUpdateRef = React . useCallback ( ( batchUpdate : BatchUpdateRef | null ) => {
145
+ batchUpdateRef . current = batchUpdate ;
146
+ tryFlushBatch ( ) ;
147
+ } , [ ] ) ;
148
+
149
+ // Task list
150
+
151
+ const batchUpdate : BatchTask = ( key , callback ) => {
152
+ batchUpdateTasksRef . current . push ( [ key , callback ] ) ;
153
+ tryFlushBatch ( ) ;
154
+ } ;
155
+
156
+ setBatchUpdate ( batchUpdate ) ;
157
+
158
+ // ========================== Unmount ===========================
121
159
React . useEffect (
122
160
( ) => ( ) => destroyForm ( clearOnDestroy ) ,
123
161
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -146,6 +184,7 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
146
184
prevFieldsRef . current = fields ;
147
185
} , [ fields , formInstance ] ) ;
148
186
187
+ // =========================== Render ===========================
149
188
const formContextValue = React . useMemo (
150
189
( ) => ( {
151
190
...( formInstance as InternalFormInstance ) ,
@@ -157,6 +196,7 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
157
196
const wrapperNode = (
158
197
< ListContext . Provider value = { null } >
159
198
< FieldContext . Provider value = { formContextValue } > { childrenNode } </ FieldContext . Provider >
199
+ < BatchUpdate ref = { setBatchUpdateRef } />
160
200
</ ListContext . Provider >
161
201
) ;
162
202
0 commit comments