@@ -118,7 +118,6 @@ export interface RendererOptions<
118
118
parentSuspense ?: SuspenseBoundary | null ,
119
119
unmountChildren ?: UnmountChildrenFn
120
120
) : void
121
- forcePatchProp ?( el : HostElement , key : string ) : boolean
122
121
insert ( el : HostNode , parent : HostElement , anchor ?: HostNode | null ) : void
123
122
remove ( el : HostNode ) : void
124
123
createElement (
@@ -288,99 +287,6 @@ export const queuePostRenderEffect = __FEATURE_SUSPENSE__
288
287
? queueEffectWithSuspense
289
288
: queuePostFlushCb
290
289
291
- export const setRef = (
292
- rawRef : VNodeNormalizedRef ,
293
- oldRawRef : VNodeNormalizedRef | null ,
294
- parentSuspense : SuspenseBoundary | null ,
295
- vnode : VNode ,
296
- isUnmount = false
297
- ) => {
298
- if ( isArray ( rawRef ) ) {
299
- rawRef . forEach ( ( r , i ) =>
300
- setRef (
301
- r ,
302
- oldRawRef && ( isArray ( oldRawRef ) ? oldRawRef [ i ] : oldRawRef ) ,
303
- parentSuspense ,
304
- vnode ,
305
- isUnmount
306
- )
307
- )
308
- return
309
- }
310
-
311
- if ( isAsyncWrapper ( vnode ) && ! isUnmount ) {
312
- // when mounting async components, nothing needs to be done,
313
- // because the template ref is forwarded to inner component
314
- return
315
- }
316
-
317
- const refValue =
318
- vnode . shapeFlag & ShapeFlags . STATEFUL_COMPONENT
319
- ? getExposeProxy ( vnode . component ! ) || vnode . component ! . proxy
320
- : vnode . el
321
- const value = isUnmount ? null : refValue
322
-
323
- const { i : owner , r : ref } = rawRef
324
- if ( __DEV__ && ! owner ) {
325
- warn (
326
- `Missing ref owner context. ref cannot be used on hoisted vnodes. ` +
327
- `A vnode with ref must be created inside the render function.`
328
- )
329
- return
330
- }
331
- const oldRef = oldRawRef && ( oldRawRef as VNodeNormalizedRefAtom ) . r
332
- const refs = owner . refs === EMPTY_OBJ ? ( owner . refs = { } ) : owner . refs
333
- const setupState = owner . setupState
334
-
335
- // dynamic ref changed. unset old ref
336
- if ( oldRef != null && oldRef !== ref ) {
337
- if ( isString ( oldRef ) ) {
338
- refs [ oldRef ] = null
339
- if ( hasOwn ( setupState , oldRef ) ) {
340
- setupState [ oldRef ] = null
341
- }
342
- } else if ( isRef ( oldRef ) ) {
343
- oldRef . value = null
344
- }
345
- }
346
-
347
- if ( isString ( ref ) ) {
348
- const doSet = ( ) => {
349
- if ( __COMPAT__ && isCompatEnabled ( DeprecationTypes . V_FOR_REF , owner ) ) {
350
- registerLegacyRef ( refs , ref , refValue , owner , rawRef . f , isUnmount )
351
- } else {
352
- refs [ ref ] = value
353
- }
354
- if ( hasOwn ( setupState , ref ) ) {
355
- setupState [ ref ] = value
356
- }
357
- }
358
- // #1789: for non-null values, set them after render
359
- // null values means this is unmount and it should not overwrite another
360
- // ref with the same key
361
- if ( value ) {
362
- ; ( doSet as SchedulerJob ) . id = - 1
363
- queuePostRenderEffect ( doSet , parentSuspense )
364
- } else {
365
- doSet ( )
366
- }
367
- } else if ( isRef ( ref ) ) {
368
- const doSet = ( ) => {
369
- ref . value = value
370
- }
371
- if ( value ) {
372
- ; ( doSet as SchedulerJob ) . id = - 1
373
- queuePostRenderEffect ( doSet , parentSuspense )
374
- } else {
375
- doSet ( )
376
- }
377
- } else if ( isFunction ( ref ) ) {
378
- callWithErrorHandling ( ref , owner , ErrorCodes . FUNCTION_REF , [ value , refs ] )
379
- } else if ( __DEV__ ) {
380
- warn ( 'Invalid template ref type:' , value , `(${ typeof value } )` )
381
- }
382
- }
383
-
384
290
/**
385
291
* The createRenderer function accepts two generic arguments:
386
292
* HostNode and HostElement, corresponding to Node and Element types in the
@@ -444,7 +350,6 @@ function baseCreateRenderer(
444
350
insert : hostInsert ,
445
351
remove : hostRemove ,
446
352
patchProp : hostPatchProp ,
447
- forcePatchProp : hostForcePatchProp ,
448
353
createElement : hostCreateElement ,
449
354
createText : hostCreateText ,
450
355
createComment : hostCreateComment ,
@@ -767,7 +672,7 @@ function baseCreateRenderer(
767
672
// props
768
673
if ( props ) {
769
674
for ( const key in props ) {
770
- if ( ! isReservedProp ( key ) ) {
675
+ if ( key !== 'value' && ! isReservedProp ( key ) ) {
771
676
hostPatchProp (
772
677
el ,
773
678
key ,
@@ -781,6 +686,18 @@ function baseCreateRenderer(
781
686
)
782
687
}
783
688
}
689
+ /**
690
+ * Special case for setting value on DOM elements:
691
+ * - it can be order-sensitive (e.g. should be set *after* min/max, #2325, #4024)
692
+ * - it needs to be forced (#1471)
693
+ * #2353 proposes adding another renderer option to configure this, but
694
+ * the properties affects are so finite it is worth special casing it
695
+ * here to reduce the complexity. (Special casing it also should not
696
+ * affect non-DOM renderers)
697
+ */
698
+ if ( 'value' in props ) {
699
+ hostPatchProp ( el , 'value' , null , props . value )
700
+ }
784
701
if ( ( vnodeHook = props . onVnodeBeforeMount ) ) {
785
702
invokeVNodeHook ( vnodeHook , parentComponent , vnode )
786
703
}
@@ -967,10 +884,8 @@ function baseCreateRenderer(
967
884
const key = propsToUpdate [ i ]
968
885
const prev = oldProps [ key ]
969
886
const next = newProps [ key ]
970
- if (
971
- next !== prev ||
972
- ( hostForcePatchProp && hostForcePatchProp ( el , key ) )
973
- ) {
887
+ // #1471 force patch value
888
+ if ( next !== prev || key === 'value' ) {
974
889
hostPatchProp (
975
890
el ,
976
891
key ,
@@ -1104,10 +1019,8 @@ function baseCreateRenderer(
1104
1019
if ( isReservedProp ( key ) ) continue
1105
1020
const next = newProps [ key ]
1106
1021
const prev = oldProps [ key ]
1107
- if (
1108
- next !== prev ||
1109
- ( hostForcePatchProp && hostForcePatchProp ( el , key ) )
1110
- ) {
1022
+ // defer patching value
1023
+ if ( next !== prev && key !== 'value' ) {
1111
1024
hostPatchProp (
1112
1025
el ,
1113
1026
key ,
@@ -1138,6 +1051,9 @@ function baseCreateRenderer(
1138
1051
}
1139
1052
}
1140
1053
}
1054
+ if ( 'value' in newProps ) {
1055
+ hostPatchProp ( el , 'value' , oldProps . value , newProps . value )
1056
+ }
1141
1057
}
1142
1058
}
1143
1059
@@ -2418,6 +2334,99 @@ function baseCreateRenderer(
2418
2334
}
2419
2335
}
2420
2336
2337
+ export function setRef (
2338
+ rawRef : VNodeNormalizedRef ,
2339
+ oldRawRef : VNodeNormalizedRef | null ,
2340
+ parentSuspense : SuspenseBoundary | null ,
2341
+ vnode : VNode ,
2342
+ isUnmount = false
2343
+ ) {
2344
+ if ( isArray ( rawRef ) ) {
2345
+ rawRef . forEach ( ( r , i ) =>
2346
+ setRef (
2347
+ r ,
2348
+ oldRawRef && ( isArray ( oldRawRef ) ? oldRawRef [ i ] : oldRawRef ) ,
2349
+ parentSuspense ,
2350
+ vnode ,
2351
+ isUnmount
2352
+ )
2353
+ )
2354
+ return
2355
+ }
2356
+
2357
+ if ( isAsyncWrapper ( vnode ) && ! isUnmount ) {
2358
+ // when mounting async components, nothing needs to be done,
2359
+ // because the template ref is forwarded to inner component
2360
+ return
2361
+ }
2362
+
2363
+ const refValue =
2364
+ vnode . shapeFlag & ShapeFlags . STATEFUL_COMPONENT
2365
+ ? getExposeProxy ( vnode . component ! ) || vnode . component ! . proxy
2366
+ : vnode . el
2367
+ const value = isUnmount ? null : refValue
2368
+
2369
+ const { i : owner , r : ref } = rawRef
2370
+ if ( __DEV__ && ! owner ) {
2371
+ warn (
2372
+ `Missing ref owner context. ref cannot be used on hoisted vnodes. ` +
2373
+ `A vnode with ref must be created inside the render function.`
2374
+ )
2375
+ return
2376
+ }
2377
+ const oldRef = oldRawRef && ( oldRawRef as VNodeNormalizedRefAtom ) . r
2378
+ const refs = owner . refs === EMPTY_OBJ ? ( owner . refs = { } ) : owner . refs
2379
+ const setupState = owner . setupState
2380
+
2381
+ // dynamic ref changed. unset old ref
2382
+ if ( oldRef != null && oldRef !== ref ) {
2383
+ if ( isString ( oldRef ) ) {
2384
+ refs [ oldRef ] = null
2385
+ if ( hasOwn ( setupState , oldRef ) ) {
2386
+ setupState [ oldRef ] = null
2387
+ }
2388
+ } else if ( isRef ( oldRef ) ) {
2389
+ oldRef . value = null
2390
+ }
2391
+ }
2392
+
2393
+ if ( isString ( ref ) ) {
2394
+ const doSet = ( ) => {
2395
+ if ( __COMPAT__ && isCompatEnabled ( DeprecationTypes . V_FOR_REF , owner ) ) {
2396
+ registerLegacyRef ( refs , ref , refValue , owner , rawRef . f , isUnmount )
2397
+ } else {
2398
+ refs [ ref ] = value
2399
+ }
2400
+ if ( hasOwn ( setupState , ref ) ) {
2401
+ setupState [ ref ] = value
2402
+ }
2403
+ }
2404
+ // #1789: for non-null values, set them after render
2405
+ // null values means this is unmount and it should not overwrite another
2406
+ // ref with the same key
2407
+ if ( value ) {
2408
+ ; ( doSet as SchedulerJob ) . id = - 1
2409
+ queuePostRenderEffect ( doSet , parentSuspense )
2410
+ } else {
2411
+ doSet ( )
2412
+ }
2413
+ } else if ( isRef ( ref ) ) {
2414
+ const doSet = ( ) => {
2415
+ ref . value = value
2416
+ }
2417
+ if ( value ) {
2418
+ ; ( doSet as SchedulerJob ) . id = - 1
2419
+ queuePostRenderEffect ( doSet , parentSuspense )
2420
+ } else {
2421
+ doSet ( )
2422
+ }
2423
+ } else if ( isFunction ( ref ) ) {
2424
+ callWithErrorHandling ( ref , owner , ErrorCodes . FUNCTION_REF , [ value , refs ] )
2425
+ } else if ( __DEV__ ) {
2426
+ warn ( 'Invalid template ref type:' , value , `(${ typeof value } )` )
2427
+ }
2428
+ }
2429
+
2421
2430
export function invokeVNodeHook (
2422
2431
hook : VNodeHook ,
2423
2432
instance : ComponentInternalInstance | null ,
0 commit comments