@@ -14,6 +14,7 @@ import type { FormContextProps } from './FormContext';
1414import FormContext from './FormContext' ;
1515import { isSimilar } from './utils/valueUtil' ;
1616import ListContext from './ListContext' ;
17+ import BatchUpdate , { BatchTask , type BatchUpdateRef } from './BatchUpdate' ;
1718
1819type BaseFormProps = Omit < React . FormHTMLAttributes < HTMLFormElement > , 'onSubmit' | 'children' > ;
1920
@@ -70,6 +71,7 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
7071 setValidateMessages,
7172 setPreserve,
7273 destroyForm,
74+ setBatchUpdate,
7375 } = ( formInstance as InternalFormInstance ) . getInternalHooks ( HOOK_MARK ) ;
7476
7577 // Pass ref with form instance
@@ -118,6 +120,42 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
118120 mountRef . current = true ;
119121 }
120122
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 ===========================
121159 React . useEffect (
122160 ( ) => ( ) => destroyForm ( clearOnDestroy ) ,
123161 // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -146,6 +184,7 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
146184 prevFieldsRef . current = fields ;
147185 } , [ fields , formInstance ] ) ;
148186
187+ // =========================== Render ===========================
149188 const formContextValue = React . useMemo (
150189 ( ) => ( {
151190 ...( formInstance as InternalFormInstance ) ,
@@ -157,6 +196,7 @@ const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
157196 const wrapperNode = (
158197 < ListContext . Provider value = { null } >
159198 < FieldContext . Provider value = { formContextValue } > { childrenNode } </ FieldContext . Provider >
199+ < BatchUpdate ref = { setBatchUpdateRef } />
160200 </ ListContext . Provider >
161201 ) ;
162202
0 commit comments