serializeInner,
createApp,
provide,
- inject
+ inject,
+ watch
} from '@vue/runtime-test'
import { render as domRender, nextTick } from 'vue'
expect(serializeInner(root)).toMatch('<div>60000000100000111</div>')
})
+
+ // #3474
+ test('should cache the value returned from the default factory to avoid unnecessary watcher trigger', async () => {
+ let count = 0
+ const Comp = {
+ props: {
+ foo: {
+ type: Object,
+ default: () => ({ val: 1 })
+ },
+ bar: Number
+ },
+ setup(props: any) {
+ watch(
+ () => props.foo,
+ () => {
+ count++
+ }
+ )
+ return () => h('h1', [props.foo.val, props.bar])
+ }
+ }
+
+ const foo = ref()
+ const bar = ref(0)
+ const app = createApp({
+ render: () => h(Comp, { foo: foo.value, bar: bar.value })
+ })
+
+ const root = nodeOps.createElement('div')
+ app.mount(root)
+ expect(serializeInner(root)).toMatch(`<h1>10</h1>`)
+ expect(count).toBe(0)
+
+ bar.value++
+ await nextTick()
+ expect(serializeInner(root)).toMatch(`<h1>11</h1>`)
+ expect(count).toBe(0)
+ })
})
* @internal
*/
emitted: Record<string, boolean> | null
-
+ /**
+ * used for caching the value returned from props default factory functions to
+ * avoid unnecessary watcher trigger
+ * @internal
+ */
+ propsDefaults: Data
/**
* setup related
* @internal
emit: null as any, // to be set immediately
emitted: null,
+ // props default value
+ propsDefaults: EMPTY_OBJ,
+
// state
ctx: EMPTY_OBJ,
data: EMPTY_OBJ,
const props: Data = {}
const attrs: Data = {}
def(attrs, InternalObjectKey, 1)
+
+ instance.propsDefaults = Object.create(null)
+
setFullProps(instance, rawProps, props, attrs)
// validation
if (__DEV__) {
if (hasDefault && value === undefined) {
const defaultValue = opt.default
if (opt.type !== Function && isFunction(defaultValue)) {
- setCurrentInstance(instance)
- value = defaultValue(props)
- setCurrentInstance(null)
+ const { propsDefaults } = instance
+ if (key in propsDefaults) {
+ value = propsDefaults[key]
+ } else {
+ setCurrentInstance(instance)
+ value = propsDefaults[key] = defaultValue(props)
+ setCurrentInstance(null)
+ }
} else {
value = defaultValue
}