Skip to content

Commit 171cfa4

Browse files
committed
fix(runtime-core): should not cast prop value if prop did not change
fix #999
1 parent 36d77f9 commit 171cfa4

File tree

3 files changed

+41
-12
lines changed

3 files changed

+41
-12
lines changed

packages/runtime-core/__tests__/componentProps.spec.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,15 @@ describe('component props', () => {
156156

157157
test('default value', () => {
158158
let proxy: any
159+
const defaultFn = jest.fn(() => ({ a: 1 }))
160+
159161
const Comp = {
160162
props: {
161163
foo: {
162164
default: 1
163165
},
164166
bar: {
165-
default: () => ({ a: 1 })
167+
default: defaultFn
166168
}
167169
},
168170
render() {
@@ -173,19 +175,32 @@ describe('component props', () => {
173175
const root = nodeOps.createElement('div')
174176
render(h(Comp, { foo: 2 }), root)
175177
expect(proxy.foo).toBe(2)
178+
const prevBar = proxy.bar
179+
expect(proxy.bar).toEqual({ a: 1 })
180+
expect(defaultFn).toHaveBeenCalledTimes(1)
181+
182+
// #999: updates should not cause default factory of unchanged prop to be
183+
// called again
184+
render(h(Comp, { foo: 3 }), root)
185+
expect(proxy.foo).toBe(3)
176186
expect(proxy.bar).toEqual({ a: 1 })
187+
expect(proxy.bar).toBe(prevBar)
188+
expect(defaultFn).toHaveBeenCalledTimes(1)
177189

178190
render(h(Comp, { bar: { b: 2 } }), root)
179191
expect(proxy.foo).toBe(1)
180192
expect(proxy.bar).toEqual({ b: 2 })
193+
expect(defaultFn).toHaveBeenCalledTimes(1)
181194

182195
render(h(Comp, { foo: 3, bar: { b: 3 } }), root)
183196
expect(proxy.foo).toBe(3)
184197
expect(proxy.bar).toEqual({ b: 3 })
198+
expect(defaultFn).toHaveBeenCalledTimes(1)
185199

186200
render(h(Comp, { bar: { b: 4 } }), root)
187201
expect(proxy.foo).toBe(1)
188202
expect(proxy.bar).toEqual({ b: 4 })
203+
expect(defaultFn).toHaveBeenCalledTimes(1)
189204
})
190205

191206
test('optimized props updates', async () => {

packages/runtime-core/src/componentProps.ts

+23-10
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ export function initProps(
130130
export function updateProps(
131131
instance: ComponentInternalInstance,
132132
rawProps: Data | null,
133+
rawPrevProps: Data | null,
133134
optimized: boolean
134135
) {
135136
const {
@@ -184,20 +185,26 @@ export function updateProps(
184185
((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey)))
185186
) {
186187
if (options) {
187-
props[key] = resolvePropValue(
188-
options,
189-
rawProps || EMPTY_OBJ,
190-
key,
191-
undefined
192-
)
188+
if (rawPrevProps && rawPrevProps[kebabKey!] !== undefined) {
189+
props[key] = resolvePropValue(
190+
options,
191+
rawProps || EMPTY_OBJ,
192+
key,
193+
undefined
194+
)
195+
}
193196
} else {
194197
delete props[key]
195198
}
196199
}
197200
}
198-
for (const key in attrs) {
199-
if (!rawProps || !hasOwn(rawProps, key)) {
200-
delete attrs[key]
201+
// in the case of functional component w/o props declaration, props and
202+
// attrs point to the same object so it should already have been updated.
203+
if (attrs !== rawCurrentProps) {
204+
for (const key in attrs) {
205+
if (!rawProps || !hasOwn(rawProps, key)) {
206+
delete attrs[key]
207+
}
201208
}
202209
}
203210
}
@@ -240,9 +247,15 @@ function setFullProps(
240247
}
241248

242249
if (needCastKeys) {
250+
const rawCurrentProps = toRaw(props)
243251
for (let i = 0; i < needCastKeys.length; i++) {
244252
const key = needCastKeys[i]
245-
props[key] = resolvePropValue(options!, props, key, props[key])
253+
props[key] = resolvePropValue(
254+
options!,
255+
rawCurrentProps,
256+
key,
257+
rawCurrentProps[key]
258+
)
246259
}
247260
}
248261
}

packages/runtime-core/src/renderer.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1246,9 +1246,10 @@ function baseCreateRenderer(
12461246
optimized: boolean
12471247
) => {
12481248
nextVNode.component = instance
1249+
const prevProps = instance.vnode.props
12491250
instance.vnode = nextVNode
12501251
instance.next = null
1251-
updateProps(instance, nextVNode.props, optimized)
1252+
updateProps(instance, nextVNode.props, prevProps, optimized)
12521253
updateSlots(instance, nextVNode.children)
12531254
}
12541255

0 commit comments

Comments
 (0)