expect(serializeInner(root)).toMatch(`<div class="baz"></div>`)
})
+ // #4161
+ it('context.attrs in child component slots', async () => {
+ const toggle = ref(true)
+
+ const Parent = {
+ render: () => h(Child, toggle.value ? { id: 'foo' } : { class: 'baz' })
+ }
+
+ const Wrapper = {
+ render(this: any) {
+ return this.$slots.default()
+ }
+ }
+
+ const Child = {
+ inheritAttrs: false,
+ setup(_: any, { attrs }: any) {
+ return () => {
+ const vnode = h(Wrapper, null, {
+ default: () => [h('div', attrs)],
+ _: 1 // mark stable slots
+ })
+ vnode.dynamicChildren = [] // force optimized mode
+ return vnode
+ }
+ }
+ }
+
+ const root = nodeOps.createElement('div')
+ render(h(Parent), root)
+ expect(serializeInner(root)).toMatch(`<div id="foo"></div>`)
+
+ // should update even though it's not reactive
+ toggle.value = false
+ await nextTick()
+ expect(serializeInner(root)).toMatch(`<div class="baz"></div>`)
+ })
+
it('context.slots', async () => {
const id = ref('foo')
shallowReadonly,
proxyRefs,
EffectScope,
- markRaw
+ markRaw,
+ track,
+ TrackOpTypes
} from '@vue/reactivity'
import {
ComponentPublicInstance,
}
}
-const attrDevProxyHandlers: ProxyHandler<Data> = {
- get: (target, key: string) => {
- markAttrsAccessed()
- return target[key]
- },
- set: () => {
- warn(`setupContext.attrs is readonly.`)
- return false
- },
- deleteProperty: () => {
- warn(`setupContext.attrs is readonly.`)
- return false
- }
+function createAttrsProxy(instance: ComponentInternalInstance): Data {
+ return new Proxy(
+ instance.attrs,
+ __DEV__
+ ? {
+ get(target, key: string) {
+ markAttrsAccessed()
+ track(instance, TrackOpTypes.GET, '$attrs')
+ return target[key]
+ },
+ set() {
+ warn(`setupContext.attrs is readonly.`)
+ return false
+ },
+ deleteProperty() {
+ warn(`setupContext.attrs is readonly.`)
+ return false
+ }
+ }
+ : {
+ get(target, key: string) {
+ track(instance, TrackOpTypes.GET, '$attrs')
+ return target[key]
+ }
+ }
+ )
}
export function createSetupContext(
instance.exposed = exposed || {}
}
+ let attrs: Data
if (__DEV__) {
- let attrs: Data
// We use getters in dev in case libs like test-utils overwrite instance
// properties (overwrites should not be done in prod)
return Object.freeze({
get attrs() {
- return (
- attrs || (attrs = new Proxy(instance.attrs, attrDevProxyHandlers))
- )
+ return attrs || (attrs = createAttrsProxy(instance))
},
get slots() {
return shallowReadonly(instance.slots)
})
} else {
return {
- attrs: instance.attrs,
+ get attrs() {
+ return attrs || (attrs = createAttrsProxy(instance))
+ },
slots: instance.slots,
emit: instance.emit,
expose