@@ -7,10 +7,12 @@ import type {
7
7
InternalNamePath ,
8
8
NamePath ,
9
9
Store ,
10
+ WatchCallBack ,
10
11
WatchOptions ,
11
12
} from './interface' ;
12
13
import { isFormInstance } from './utils/typeUtil' ;
13
14
import { getNamePath , getValue } from './utils/valueUtil' ;
15
+ import { useEvent } from '@rc-component/util' ;
14
16
15
17
type ReturnPromise < T > = T extends Promise < infer ValueType > ? ValueType : never ;
16
18
type GetGeneric < TForm extends FormInstance > = ReturnPromise < ReturnType < TForm [ 'validateFields' ] > > ;
@@ -23,19 +25,6 @@ export function stringify(value: any) {
23
25
}
24
26
}
25
27
26
- const useWatchWarning =
27
- process . env . NODE_ENV !== 'production'
28
- ? ( namePath : InternalNamePath ) => {
29
- const fullyStr = namePath . join ( '__RC_FIELD_FORM_SPLIT__' ) ;
30
- const nameStrRef = useRef ( fullyStr ) ;
31
-
32
- warning (
33
- nameStrRef . current === fullyStr ,
34
- '`useWatch` is not support dynamic `namePath`. Please provide static instead.' ,
35
- ) ;
36
- }
37
- : ( ) => { } ;
38
-
39
28
function useWatch <
40
29
TDependencies1 extends keyof GetGeneric < TForm > ,
41
30
TForm extends FormInstance ,
@@ -123,56 +112,57 @@ function useWatch(
123
112
) ;
124
113
}
125
114
126
- const namePath = getNamePath ( dependencies ) ;
127
- const namePathRef = useRef ( namePath ) ;
128
- namePathRef . current = namePath ;
129
-
130
- useWatchWarning ( namePath ) ;
131
-
132
- useEffect (
133
- ( ) => {
134
- // Skip if not exist form instance
135
- if ( ! isValidForm ) {
136
- return ;
137
- }
138
-
139
- const { getFieldsValue, getInternalHooks } = formInstance ;
140
- const { registerWatch } = getInternalHooks ( HOOK_MARK ) ;
141
-
142
- const getWatchValue = ( values : any , allValues : any ) => {
143
- const watchValue = options . preserve ? allValues : values ;
144
- return typeof dependencies === 'function'
145
- ? dependencies ( watchValue )
146
- : getValue ( watchValue , namePathRef . current ) ;
147
- } ;
148
-
149
- const cancelRegister = registerWatch ( ( values , allValues ) => {
150
- const newValue = getWatchValue ( values , allValues ) ;
151
- const nextValueStr = stringify ( newValue ) ;
152
-
153
- // Compare stringify in case it's nest object
154
- if ( valueStrRef . current !== nextValueStr ) {
155
- valueStrRef . current = nextValueStr ;
156
- setValue ( newValue ) ;
157
- }
158
- } ) ;
159
-
160
- // TODO: We can improve this perf in future
161
- const initialValue = getWatchValue ( getFieldsValue ( ) , getFieldsValue ( true ) ) ;
162
-
163
- // React 18 has the bug that will queue update twice even the value is not changed
164
- // ref: https://github.com/facebook/react/issues/27213
165
- if ( value !== initialValue ) {
166
- setValue ( initialValue ) ;
167
- }
168
-
169
- return cancelRegister ;
170
- } ,
171
-
172
- // We do not need re-register since namePath content is the same
115
+ // ============================== Form ==============================
116
+ const { getFieldsValue, getInternalHooks } = formInstance ;
117
+ const { registerWatch } = getInternalHooks ( HOOK_MARK ) ;
118
+
119
+ // ============================= Update =============================
120
+ const triggerUpdate = useEvent ( ( values ?: any , allValues ?: any ) => {
121
+ const watchValue = options . preserve
122
+ ? ( allValues ?? getFieldsValue ( true ) )
123
+ : ( values ?? getFieldsValue ( ) ) ;
124
+
125
+ const nextValue =
126
+ typeof dependencies === 'function'
127
+ ? dependencies ( watchValue )
128
+ : getValue ( watchValue , getNamePath ( dependencies ) ) ;
129
+
130
+ if ( stringify ( value ) !== stringify ( nextValue ) ) {
131
+ setValue ( nextValue ) ;
132
+ }
133
+ } ) ;
134
+
135
+ // ============================= Effect =============================
136
+ const flattenDeps =
137
+ typeof dependencies === 'function' ? dependencies : JSON . stringify ( dependencies ) ;
138
+
139
+ // Deps changed
140
+ useEffect ( ( ) => {
141
+ // Skip if not exist form instance
142
+ if ( ! isValidForm ) {
143
+ return ;
144
+ }
145
+
146
+ triggerUpdate ( ) ;
147
+
148
+ // eslint-disable-next-line react-hooks/exhaustive-deps
149
+ } , [ isValidForm , flattenDeps ] ) ;
150
+
151
+ // Value changed
152
+ useEffect ( ( ) => {
153
+ // Skip if not exist form instance
154
+ if ( ! isValidForm ) {
155
+ return ;
156
+ }
157
+
158
+ const cancelRegister = registerWatch ( ( values , allValues ) => {
159
+ triggerUpdate ( values , allValues ) ;
160
+ } ) ;
161
+
162
+ return cancelRegister ;
163
+
173
164
// eslint-disable-next-line react-hooks/exhaustive-deps
174
- [ isValidForm ] ,
175
- ) ;
165
+ } , [ isValidForm ] ) ;
176
166
177
167
return value ;
178
168
}
0 commit comments