raw: () => T
deps: Array<Dep>
options: ReactiveEffectOptions
+ allowRecurse: boolean
}
export interface ReactiveEffectOptions {
}
} as ReactiveEffect
effect.id = uid++
+ effect.allowRecurse = !!options.allowRecurse
effect._isEffect = true
effect.active = true
effect.raw = fn
const add = (effectsToAdd: Set<ReactiveEffect> | undefined) => {
if (effectsToAdd) {
effectsToAdd.forEach(effect => {
- if (effect !== activeEffect || effect.options.allowRecurse) {
+ if (effect !== activeEffect || effect.allowRecurse) {
effects.add(effect)
}
})
VNode,
provide,
inject,
- Ref
+ Ref,
+ watch,
+ SetupContext
} from '@vue/runtime-test'
describe('renderer: component', () => {
})
// #2170
- test('should have access to instance’s “$el” property in watcher when setting instance data', async () => {
+ test('should have access to instance’s “$el” property in watcher when rendereing with watched prop', async () => {
function returnThis(this: any) {
return this
}
- const dataWatchSpy = jest.fn(returnThis)
+ const propWatchSpy = jest.fn(returnThis)
let instance: any
const Comp = {
- data() {
- return {
- testData: undefined
- }
+ props: {
+ testProp: String
},
watch: {
- testData() {
+ testProp() {
// @ts-ignore
- dataWatchSpy(this.$el)
+ propWatchSpy(this.$el)
}
},
const root = nodeOps.createElement('div')
render(h(Comp), root)
+ await nextTick()
+ expect(propWatchSpy).not.toHaveBeenCalled()
- expect(dataWatchSpy).not.toHaveBeenCalled()
- instance.testData = 'data'
-
+ render(h(Comp, { testProp: 'prop ' }), root)
await nextTick()
- expect(dataWatchSpy).toHaveBeenCalledWith(instance.$el)
+ expect(propWatchSpy).toHaveBeenCalledWith(instance.$el)
})
- // #2170
- test('should have access to instance’s “$el” property in watcher when rendereing with watched prop', async () => {
- function returnThis(this: any) {
- return this
- }
- const propWatchSpy = jest.fn(returnThis)
- let instance: any
- const Comp = {
- props: {
- testProp: String
- },
+ // #2200
+ test('component child updating parent state in pre-flush should trigger parent re-render', async () => {
+ const outer = ref(0)
+ const App = {
+ setup() {
+ const inner = ref(0)
- watch: {
- testProp() {
- // @ts-ignore
- propWatchSpy(this.$el)
+ return () => {
+ return [
+ h('div', inner.value),
+ h(Child, {
+ value: outer.value,
+ onUpdate: (val: number) => (inner.value = val)
+ })
+ ]
}
- },
+ }
+ }
- created() {
- instance = this
- },
+ const Child = {
+ props: ['value'],
+ setup(props: any, { emit }: SetupContext) {
+ watch(() => props.value, (val: number) => emit('update', val))
- render() {
- return h('div')
+ return () => {
+ return h('div', props.value)
+ }
}
}
const root = nodeOps.createElement('div')
+ render(h(App), root)
+ expect(serializeInner(root)).toBe(`<div>0</div><div>0</div>`)
- render(h(Comp), root)
- await nextTick()
- expect(propWatchSpy).not.toHaveBeenCalled()
-
- render(h(Comp, { testProp: 'prop ' }), root)
+ outer.value++
await nextTick()
- expect(propWatchSpy).toHaveBeenCalledWith(instance.$el)
+ expect(serializeInner(root)).toBe(`<div>1</div><div>1</div>`)
})
})