+60
-8
lines changedFilter options
+60
-8
lines changed Original file line number Diff line number Diff line change
@@ -12,7 +12,8 @@ import {
12
12
provide,
13
13
inject,
14
14
watch,
15
-
toRefs
15
+
toRefs,
16
+
SetupContext
16
17
} from '@vue/runtime-test'
17
18
import { render as domRender, nextTick } from 'vue'
18
19
@@ -508,4 +509,51 @@ describe('component props', () => {
508
509
await nextTick()
509
510
expect(changeSpy).toHaveBeenCalledTimes(1)
510
511
})
512
+
513
+
// #3371
514
+
test(`avoid double-setting props when casting`, async () => {
515
+
const Parent = {
516
+
setup(props: any, { slots }: SetupContext) {
517
+
const childProps = ref()
518
+
const registerChildProps = (props: any) => {
519
+
childProps.value = props
520
+
}
521
+
provide('register', registerChildProps)
522
+
523
+
return () => {
524
+
// access the child component's props
525
+
childProps.value && childProps.value.foo
526
+
return slots.default!()
527
+
}
528
+
}
529
+
}
530
+
531
+
const Child = {
532
+
props: {
533
+
foo: {
534
+
type: Boolean,
535
+
required: false
536
+
}
537
+
},
538
+
setup(props: { foo: boolean }) {
539
+
const register = inject('register') as any
540
+
// 1. change the reactivity data of the parent component
541
+
// 2. register its own props to the parent component
542
+
register(props)
543
+
544
+
return () => 'foo'
545
+
}
546
+
}
547
+
548
+
const App = {
549
+
setup() {
550
+
return () => h(Parent, () => h(Child as any, { foo: '' }, () => null))
551
+
}
552
+
}
553
+
554
+
const root = nodeOps.createElement('div')
555
+
render(h(App), root)
556
+
await nextTick()
557
+
expect(serializeInner(root)).toBe(`foo`)
558
+
})
511
559
})
Original file line number Diff line number Diff line change
@@ -312,6 +312,7 @@ function setFullProps(
312
312
) {
313
313
const [options, needCastKeys] = instance.propsOptions
314
314
let hasAttrsChanged = false
315
+
let rawCastValues: Data | undefined
315
316
if (rawProps) {
316
317
for (let key in rawProps) {
317
318
// key, ref are reserved and never passed down
@@ -337,7 +338,11 @@ function setFullProps(
337
338
// kebab -> camel conversion here we need to camelize the key.
338
339
let camelKey
339
340
if (options && hasOwn(options, (camelKey = camelize(key)))) {
340
-
props[camelKey] = value
341
+
if (!needCastKeys || !needCastKeys.includes(camelKey)) {
342
+
props[camelKey] = value
343
+
} else {
344
+
;(rawCastValues || (rawCastValues = {}))[camelKey] = value
345
+
}
341
346
} else if (!isEmitListener(instance.emitsOptions, key)) {
342
347
// Any non-declared (either as a prop or an emitted event) props are put
343
348
// into a separate `attrs` object for spreading. Make sure to preserve
@@ -358,14 +363,13 @@ function setFullProps(
358
363
}
359
364
360
365
if (needCastKeys) {
361
-
const rawCurrentProps = toRaw(props)
362
366
for (let i = 0; i < needCastKeys.length; i++) {
363
367
const key = needCastKeys[i]
364
368
props[key] = resolvePropValue(
365
369
options!,
366
-
rawCurrentProps,
370
+
rawCastValues || EMPTY_OBJ,
367
371
key,
368
-
rawCurrentProps[key],
372
+
rawCastValues && rawCastValues[key],
369
373
instance
370
374
)
371
375
}
@@ -408,13 +412,13 @@ function resolvePropValue(
408
412
}
409
413
// boolean casting
410
414
if (opt[BooleanFlags.shouldCast]) {
411
-
if (!hasOwn(props, key) && !hasDefault) {
412
-
value = false
413
-
} else if (
415
+
if (
414
416
opt[BooleanFlags.shouldCastTrue] &&
415
417
(value === '' || value === hyphenate(key))
416
418
) {
417
419
value = true
420
+
} else if (!hasOwn(props, key) && !hasDefault) {
421
+
value = false
418
422
}
419
423
}
420
424
}
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4