]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(vapor): destructure in `v-for`
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 15 Nov 2024 22:33:38 +0000 (06:33 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 15 Nov 2024 22:33:44 +0000 (06:33 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
packages/compiler-vapor/src/generators/for.ts
packages/runtime-vapor/__tests__/for.spec.ts
packages/runtime-vapor/src/destructure.ts

index 55354aec574e4eda8940bd7869fcaf02a3d07253..b77a3f7cdb8360e0236da11a28214e92e3d7d44b 100644 (file)
@@ -7,7 +7,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([[id, ...other], index]) => [id, other, index], (_ctx0) => {
     const n2 = t0()
-    _renderEffect(() => _setText(n2, _ctx0[0].value + _ctx0[1].value + _ctx0[2].value))
+    _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2]))
     return n2
   }), ([id, ...other], index) => (id))
   return n0
@@ -87,7 +87,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ id, ...other }, index]) => [id, other, index], (_ctx0) => {
     const n2 = t0()
-    _renderEffect(() => _setText(n2, _ctx0[0].value + _ctx0[1].value + _ctx0[2].value))
+    _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2]))
     return n2
   }), ({ id, ...other }, index) => (id))
   return n0
@@ -101,7 +101,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ foo = bar, baz: [qux = quux] }]) => [foo, qux], (_ctx0) => {
     const n2 = t0()
-    _renderEffect(() => _setText(n2, _ctx0[0].value + _ctx.bar + _ctx.baz + _ctx0[1].value + _ctx.quux))
+    _renderEffect(() => _setText(n2, _ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux))
     return n2
   }))
   return n0
index 58064e4c3d09e3b4954b4aa04af06ac3111a2cc6..45b33c7a4d0fa2fda32724539ca68784ecac7a1d 100644 (file)
@@ -130,7 +130,7 @@ describe('compiler: v-for', () => {
     )
     expect(code).matchSnapshot()
     expect(code).contains(`([{ id, ...other }, index]) => [id, other, index]`)
-    expect(code).contains(`_ctx0[0].value + _ctx0[1].value + _ctx0[2].value`)
+    expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`)
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
       source: {
@@ -163,7 +163,7 @@ describe('compiler: v-for', () => {
     )
     expect(code).matchSnapshot()
     expect(code).contains(`([[id, ...other], index]) => [id, other, index]`)
-    expect(code).contains(`_ctx0[0].value + _ctx0[1].value + _ctx0[2]`)
+    expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`)
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
       source: {
@@ -199,7 +199,7 @@ describe('compiler: v-for', () => {
     expect(code).matchSnapshot()
     expect(code).contains(`([{ foo = bar, baz: [qux = quux] }]) => [foo, qux]`)
     expect(code).contains(
-      `_ctx0[0].value + _ctx.bar + _ctx.baz + _ctx0[1].value + _ctx.quux`,
+      `_ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux`,
     )
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
index ddfd61e1b65f7f5eac1b3e64b3f8052f2d01db91..8a90901d4551f80ca104ed27354c102f54227323 100644 (file)
@@ -29,7 +29,7 @@ export function genFor(
     container,
   } = oper
 
-  let isDestructureAssignment = false
+  let isDestructure = false
   let rawValue: string | null = null
   const rawKey = key && key.content
   const rawIndex = index && index.content
@@ -39,7 +39,7 @@ export function genFor(
   let blockFn = genBlockFn()
   const simpleIdMap: Record<string, null> = genSimpleIdMap()
 
-  if (isDestructureAssignment) {
+  if (isDestructure) {
     const idMap: Record<string, null> = {}
     idsInValue.forEach(id => (idMap[id] = null))
     if (rawKey) idMap[rawKey] = null
@@ -82,7 +82,7 @@ export function genFor(
     const idsInValue = new Set<string>()
     if (value) {
       rawValue = value && value.content
-      if ((isDestructureAssignment = !!value.ast)) {
+      if ((isDestructure = !!value.ast)) {
         walkIdentifiers(
           value.ast,
           (id, _, __, ___, isLocal) => {
@@ -103,12 +103,13 @@ export function genFor(
     const idMap: Record<string, string | null> = {}
     if (context.options.prefixIdentifiers) {
       propsName = `_ctx${depth}`
+      let suffix = isDestructure ? '' : '.value'
       Array.from(idsInValue).forEach(
-        (id, idIndex) => (idMap[id] = `${propsName}[${idIndex}].value`),
+        (id, idIndex) => (idMap[id] = `${propsName}[${idIndex}]${suffix}`),
       )
-      if (rawKey) idMap[rawKey] = `${propsName}[${idsInValue.size}].value`
+      if (rawKey) idMap[rawKey] = `${propsName}[${idsInValue.size}]${suffix}`
       if (rawIndex)
-        idMap[rawIndex] = `${propsName}[${idsInValue.size + 1}].value`
+        idMap[rawIndex] = `${propsName}[${idsInValue.size + 1}]${suffix}`
     } else {
       propsName = `[${[rawValue || ((rawKey || rawIndex) && '_'), rawKey || (rawIndex && '__'), rawIndex].filter(Boolean).join(', ')}]`
     }
index 5854298acecff772d2e3f5e5afb847b4fca7c711..0ee09a9ad13e239a31dafea82c9e8fc8813028c2 100644 (file)
@@ -4,7 +4,9 @@ import {
   ref,
   renderEffect,
   shallowRef,
+  template,
   triggerRef,
+  withDestructure,
 } from '../src'
 import { makeRender } from './_utils'
 
@@ -579,4 +581,27 @@ describe('createFor', () => {
     await nextTick()
     expectCalledTimesToBe('Clear rows', 1, 0, 0, 0)
   })
+
+  test('withDestructure', () => {
+    const list = ref([{ name: 'a' }, { name: 'b' }, { name: 'c' }])
+
+    const { host } = define(() => {
+      const n1 = createFor(
+        () => list.value,
+        withDestructure(
+          ([{ name }, index]) => [name, index],
+          ctx => {
+            const span = template(`<li>${ctx[1]}. ${ctx[0]}</li>`)()
+            return span
+          },
+        ),
+        item => item.name,
+      )
+      return n1
+    }).render()
+
+    expect(host.innerHTML).toBe(
+      '<li>0. a</li><li>1. b</li><li>2. c</li><!--for-->',
+    )
+  })
 })
index 20030dd3287a11fb76b49cb4100d5dbbe8c8ca8a..8e68f453fafde20cff2a6ad29daf36286f42016b 100644 (file)
@@ -1,14 +1,18 @@
-import { shallowReactive } from '@vue/reactivity'
+import {
+  type ShallowUnwrapRef,
+  proxyRefs,
+  shallowReactive,
+} from '@vue/reactivity'
 import { renderEffect } from './renderEffect'
 
-export function withDestructure<P extends any[], R>(
-  assign: (...args: P) => any[],
+export function withDestructure<T extends any[], R>(
+  assign: (data: ShallowUnwrapRef<T>) => any[],
   block: (ctx: any[]) => R,
-): (...args: P) => R {
-  return (...args: P) => {
+): (data: T) => R {
+  return (data: T) => {
     const ctx = shallowReactive<any[]>([])
     renderEffect(() => {
-      const res = assign(...args)
+      const res = assign(proxyRefs(data))
       const len = res.length
       for (let i = 0; i < len; i++) {
         ctx[i] = res[i]