@@ -4,13 +4,13 @@ import FieldContext, { HOOK_MARK } from './FieldContext';
4
4
import type {
5
5
FormInstance ,
6
6
InternalFormInstance ,
7
- InternalNamePath ,
8
7
NamePath ,
9
8
Store ,
10
9
WatchOptions ,
11
10
} from './interface' ;
12
11
import { isFormInstance } from './utils/typeUtil' ;
13
12
import { getNamePath , getValue } from './utils/valueUtil' ;
13
+ import { useEvent } from '@rc-component/util' ;
14
14
15
15
type ReturnPromise < T > = T extends Promise < infer ValueType > ? ValueType : never ;
16
16
type GetGeneric < TForm extends FormInstance > = ReturnPromise < ReturnType < TForm [ 'validateFields' ] > > ;
@@ -23,19 +23,6 @@ export function stringify(value: any) {
23
23
}
24
24
}
25
25
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
26
function useWatch <
40
27
TDependencies1 extends keyof GetGeneric < TForm > ,
41
28
TForm extends FormInstance ,
@@ -123,56 +110,57 @@ function useWatch(
123
110
) ;
124
111
}
125
112
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
113
+ // ============================== Form ==============================
114
+ const { getFieldsValue, getInternalHooks } = formInstance ;
115
+ const { registerWatch } = getInternalHooks ( HOOK_MARK ) ;
116
+
117
+ // ============================= Update =============================
118
+ const triggerUpdate = useEvent ( ( values ?: any , allValues ?: any ) => {
119
+ const watchValue = options . preserve
120
+ ? ( allValues ?? getFieldsValue ( true ) )
121
+ : ( values ?? getFieldsValue ( ) ) ;
122
+
123
+ const nextValue =
124
+ typeof dependencies === 'function'
125
+ ? dependencies ( watchValue )
126
+ : getValue ( watchValue , getNamePath ( dependencies ) ) ;
127
+
128
+ if ( stringify ( value ) !== stringify ( nextValue ) ) {
129
+ setValue ( nextValue ) ;
130
+ }
131
+ } ) ;
132
+
133
+ // ============================= Effect =============================
134
+ const flattenDeps =
135
+ typeof dependencies === 'function' ? dependencies : JSON . stringify ( dependencies ) ;
136
+
137
+ // Deps changed
138
+ useEffect ( ( ) => {
139
+ // Skip if not exist form instance
140
+ if ( ! isValidForm ) {
141
+ return ;
142
+ }
143
+
144
+ triggerUpdate ( ) ;
145
+
146
+ // eslint-disable-next-line react-hooks/exhaustive-deps
147
+ } , [ isValidForm , flattenDeps ] ) ;
148
+
149
+ // Value changed
150
+ useEffect ( ( ) => {
151
+ // Skip if not exist form instance
152
+ if ( ! isValidForm ) {
153
+ return ;
154
+ }
155
+
156
+ const cancelRegister = registerWatch ( ( values , allValues ) => {
157
+ triggerUpdate ( values , allValues ) ;
158
+ } ) ;
159
+
160
+ return cancelRegister ;
161
+
173
162
// eslint-disable-next-line react-hooks/exhaustive-deps
174
- [ isValidForm ] ,
175
- ) ;
163
+ } , [ isValidForm ] ) ;
176
164
177
165
return value ;
178
166
}
0 commit comments