Răsfoiți Sursa

fix(vapor): destructure in `v-for`

三咲智子 Kevin Deng 1 an în urmă
părinte
comite
81b3d36304

+ 3 - 3
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap

@@ -7,7 +7,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
 export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([[id, ...other], index]) => [id, other, index], (_ctx0) => {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([[id, ...other], index]) => [id, other, index], (_ctx0) => {
     const n2 = t0()
     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
     return n2
   }), ([id, ...other], index) => (id))
   }), ([id, ...other], index) => (id))
   return n0
   return n0
@@ -87,7 +87,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
 export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ id, ...other }, index]) => [id, other, index], (_ctx0) => {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ id, ...other }, index]) => [id, other, index], (_ctx0) => {
     const n2 = t0()
     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
     return n2
   }), ({ id, ...other }, index) => (id))
   }), ({ id, ...other }, index) => (id))
   return n0
   return n0
@@ -101,7 +101,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
 export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ foo = bar, baz: [qux = quux] }]) => [foo, qux], (_ctx0) => {
   const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ foo = bar, baz: [qux = quux] }]) => [foo, qux], (_ctx0) => {
     const n2 = t0()
     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 n2
   }))
   }))
   return n0
   return n0

+ 3 - 3
packages/compiler-vapor/__tests__/transforms/vFor.spec.ts

@@ -130,7 +130,7 @@ describe('compiler: v-for', () => {
     )
     )
     expect(code).matchSnapshot()
     expect(code).matchSnapshot()
     expect(code).contains(`([{ id, ...other }, index]) => [id, other, index]`)
     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({
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
       type: IRNodeTypes.FOR,
       source: {
       source: {
@@ -163,7 +163,7 @@ describe('compiler: v-for', () => {
     )
     )
     expect(code).matchSnapshot()
     expect(code).matchSnapshot()
     expect(code).contains(`([[id, ...other], index]) => [id, other, index]`)
     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({
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
       type: IRNodeTypes.FOR,
       source: {
       source: {
@@ -199,7 +199,7 @@ describe('compiler: v-for', () => {
     expect(code).matchSnapshot()
     expect(code).matchSnapshot()
     expect(code).contains(`([{ foo = bar, baz: [qux = quux] }]) => [foo, qux]`)
     expect(code).contains(`([{ foo = bar, baz: [qux = quux] }]) => [foo, qux]`)
     expect(code).contains(
     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({
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
       type: IRNodeTypes.FOR,

+ 7 - 6
packages/compiler-vapor/src/generators/for.ts

@@ -29,7 +29,7 @@ export function genFor(
     container,
     container,
   } = oper
   } = oper
 
 
-  let isDestructureAssignment = false
+  let isDestructure = false
   let rawValue: string | null = null
   let rawValue: string | null = null
   const rawKey = key && key.content
   const rawKey = key && key.content
   const rawIndex = index && index.content
   const rawIndex = index && index.content
@@ -39,7 +39,7 @@ export function genFor(
   let blockFn = genBlockFn()
   let blockFn = genBlockFn()
   const simpleIdMap: Record<string, null> = genSimpleIdMap()
   const simpleIdMap: Record<string, null> = genSimpleIdMap()
 
 
-  if (isDestructureAssignment) {
+  if (isDestructure) {
     const idMap: Record<string, null> = {}
     const idMap: Record<string, null> = {}
     idsInValue.forEach(id => (idMap[id] = null))
     idsInValue.forEach(id => (idMap[id] = null))
     if (rawKey) idMap[rawKey] = null
     if (rawKey) idMap[rawKey] = null
@@ -82,7 +82,7 @@ export function genFor(
     const idsInValue = new Set<string>()
     const idsInValue = new Set<string>()
     if (value) {
     if (value) {
       rawValue = value && value.content
       rawValue = value && value.content
-      if ((isDestructureAssignment = !!value.ast)) {
+      if ((isDestructure = !!value.ast)) {
         walkIdentifiers(
         walkIdentifiers(
           value.ast,
           value.ast,
           (id, _, __, ___, isLocal) => {
           (id, _, __, ___, isLocal) => {
@@ -103,12 +103,13 @@ export function genFor(
     const idMap: Record<string, string | null> = {}
     const idMap: Record<string, string | null> = {}
     if (context.options.prefixIdentifiers) {
     if (context.options.prefixIdentifiers) {
       propsName = `_ctx${depth}`
       propsName = `_ctx${depth}`
+      let suffix = isDestructure ? '' : '.value'
       Array.from(idsInValue).forEach(
       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)
       if (rawIndex)
-        idMap[rawIndex] = `${propsName}[${idsInValue.size + 1}].value`
+        idMap[rawIndex] = `${propsName}[${idsInValue.size + 1}]${suffix}`
     } else {
     } else {
       propsName = `[${[rawValue || ((rawKey || rawIndex) && '_'), rawKey || (rawIndex && '__'), rawIndex].filter(Boolean).join(', ')}]`
       propsName = `[${[rawValue || ((rawKey || rawIndex) && '_'), rawKey || (rawIndex && '__'), rawIndex].filter(Boolean).join(', ')}]`
     }
     }

+ 25 - 0
packages/runtime-vapor/__tests__/for.spec.ts

@@ -4,7 +4,9 @@ import {
   ref,
   ref,
   renderEffect,
   renderEffect,
   shallowRef,
   shallowRef,
+  template,
   triggerRef,
   triggerRef,
+  withDestructure,
 } from '../src'
 } from '../src'
 import { makeRender } from './_utils'
 import { makeRender } from './_utils'
 
 
@@ -579,4 +581,27 @@ describe('createFor', () => {
     await nextTick()
     await nextTick()
     expectCalledTimesToBe('Clear rows', 1, 0, 0, 0)
     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-->',
+    )
+  })
 })
 })

+ 10 - 6
packages/runtime-vapor/src/destructure.ts

@@ -1,14 +1,18 @@
-import { shallowReactive } from '@vue/reactivity'
+import {
+  type ShallowUnwrapRef,
+  proxyRefs,
+  shallowReactive,
+} from '@vue/reactivity'
 import { renderEffect } from './renderEffect'
 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,
   block: (ctx: any[]) => R,
-): (...args: P) => R {
-  return (...args: P) => {
+): (data: T) => R {
+  return (data: T) => {
     const ctx = shallowReactive<any[]>([])
     const ctx = shallowReactive<any[]>([])
     renderEffect(() => {
     renderEffect(() => {
-      const res = assign(...args)
+      const res = assign(proxyRefs(data))
       const len = res.length
       const len = res.length
       for (let i = 0; i < len; i++) {
       for (let i = 0; i < len; i++) {
         ctx[i] = res[i]
         ctx[i] = res[i]