Skip to content

Commit 99009ee

Browse files
authoredNov 14, 2024··
fix(compiler-core): handle v-memo + v-for with functional key (#12014)
close #12013
1 parent 37300fc commit 99009ee

File tree

4 files changed

+48
-4
lines changed

4 files changed

+48
-4
lines changed
 

‎packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap

+18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3+
exports[`compiler: v-memo transform > element v-for key expression prefixing + v-memo 1`] = `
4+
"import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, isMemoSame as _isMemoSame, withMemo as _withMemo } from "vue"
5+
6+
export function render(_ctx, _cache) {
7+
return (_openBlock(), _createElementBlock("div", null, [
8+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.tableData, (data, __, ___, _cached) => {
9+
const _memo = (_ctx.getLetter(data))
10+
if (_cached && _cached.key === _ctx.getId(data) && _isMemoSame(_cached, _memo)) return _cached
11+
const _item = (_openBlock(), _createElementBlock("span", {
12+
key: _ctx.getId(data)
13+
}))
14+
_item.memo = _memo
15+
return _item
16+
}, _cache, 0), 128 /* KEYED_FRAGMENT */))
17+
]))
18+
}"
19+
`;
20+
321
exports[`compiler: v-memo transform > on component 1`] = `
422
"import { resolveComponent as _resolveComponent, createVNode as _createVNode, withMemo as _withMemo, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
523

‎packages/compiler-core/__tests__/transforms/vMemo.spec.ts

+8
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,12 @@ describe('compiler: v-memo transform', () => {
5353
),
5454
).toMatchSnapshot()
5555
})
56+
57+
test('element v-for key expression prefixing + v-memo', () => {
58+
expect(
59+
compile(
60+
`<span v-for="data of tableData" :key="getId(data)" v-memo="getLetter(data)"></span>`,
61+
),
62+
).toMatchSnapshot()
63+
})
5664
})

‎packages/compiler-core/src/transforms/transformExpression.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
isStaticPropertyKey,
2525
walkIdentifiers,
2626
} from '../babelUtils'
27-
import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
27+
import { advancePositionWithClone, findDir, isSimpleIdentifier } from '../utils'
2828
import {
2929
genPropsAccessExp,
3030
hasOwn,
@@ -54,6 +54,7 @@ export const transformExpression: NodeTransform = (node, context) => {
5454
)
5555
} else if (node.type === NodeTypes.ELEMENT) {
5656
// handle directives on element
57+
const memo = findDir(node, 'memo')
5758
for (let i = 0; i < node.props.length; i++) {
5859
const dir = node.props[i]
5960
// do not process for v-on & v-for since they are special handled
@@ -65,7 +66,14 @@ export const transformExpression: NodeTransform = (node, context) => {
6566
if (
6667
exp &&
6768
exp.type === NodeTypes.SIMPLE_EXPRESSION &&
68-
!(dir.name === 'on' && arg)
69+
!(dir.name === 'on' && arg) &&
70+
// key has been processed in transformFor(vMemo + vFor)
71+
!(
72+
memo &&
73+
arg &&
74+
arg.type === NodeTypes.SIMPLE_EXPRESSION &&
75+
arg.content === 'key'
76+
)
6977
) {
7078
dir.exp = processExpression(
7179
exp,

‎packages/compiler-core/src/transforms/vFor.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,27 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform(
6363
const isTemplate = isTemplateNode(node)
6464
const memo = findDir(node, 'memo')
6565
const keyProp = findProp(node, `key`, false, true)
66-
if (keyProp && keyProp.type === NodeTypes.DIRECTIVE && !keyProp.exp) {
66+
const isDirKey = keyProp && keyProp.type === NodeTypes.DIRECTIVE
67+
if (isDirKey && !keyProp.exp) {
6768
// resolve :key shorthand #10882
6869
transformBindShorthand(keyProp, context)
6970
}
70-
const keyExp =
71+
let keyExp =
7172
keyProp &&
7273
(keyProp.type === NodeTypes.ATTRIBUTE
7374
? keyProp.value
7475
? createSimpleExpression(keyProp.value.content, true)
7576
: undefined
7677
: keyProp.exp)
78+
79+
if (memo && keyExp && isDirKey) {
80+
if (!__BROWSER__) {
81+
keyProp.exp = keyExp = processExpression(
82+
keyExp as SimpleExpressionNode,
83+
context,
84+
)
85+
}
86+
}
7787
const keyProperty =
7888
keyProp && keyExp ? createObjectProperty(`key`, keyExp) : null
7989

0 commit comments

Comments
 (0)
Please sign in to comment.