Jelajahi Sumber

fix(runtime-vapor): v-for move list items are not always effective (#121)

Rizumu Ayaka 2 tahun lalu
induk
melakukan
ccdc634c24

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

@@ -0,0 +1,62 @@
+import {
+  computed,
+  createFor,
+  createTextNode,
+  nextTick,
+  ref,
+  renderEffect,
+  setText,
+} from '../src'
+import { makeRender } from './_utils'
+
+const define = makeRender()
+
+describe('createFor', () => {
+  test('basic', async () => {
+    const list = ref([{ name: '1' }, { name: '2' }, { name: '3' }])
+    const sort = ref(false)
+    const sortedList = computed(() =>
+      sort.value ? Array.from(list.value).reverse() : list.value,
+    )
+
+    const { host } = define(() => {
+      const n1 = createFor(
+        () => sortedList.value,
+        block => {
+          const n3 = createTextNode()
+          renderEffect(() => {
+            const [item] = block.s
+            setText(n3, item.name)
+          })
+          return [n3]
+        },
+      )
+      return [n1]
+    }).render()
+
+    expect(host.innerHTML).toBe('123<!--for-->')
+
+    // add
+    list.value.push({ name: '4' })
+    await nextTick()
+    expect(host.innerHTML).toBe('1234<!--for-->')
+
+    // move
+    sort.value = true
+    await nextTick()
+    expect(host.innerHTML).toBe('4321<!--for-->')
+    sort.value = false
+    await nextTick()
+    expect(host.innerHTML).toBe('1234<!--for-->')
+
+    // change
+    list.value[0].name = 'a'
+    await nextTick()
+    expect(host.innerHTML).toBe('a234<!--for-->')
+
+    // remove
+    list.value = []
+    await nextTick()
+    expect(host.innerHTML).toBe('<!--for-->')
+  })
+})

+ 1 - 3
packages/runtime-vapor/src/for.ts

@@ -6,7 +6,6 @@ import { type Block, type Fragment, fragmentKey } from './render'
 
 interface ForBlock extends Fragment {
   scope: EffectScope
-  item: any
   s: [any, number] // state, use short key since it's used a lot in generated code
   update: () => void
   key: any
@@ -41,7 +40,6 @@ export const createFor = (
       nodes: null as any,
       update: null as any,
       scope,
-      item,
       s: [item, index],
       key: getKey && getKey(item, index),
       memo: getMemo && getMemo(item),
@@ -99,7 +97,7 @@ export const createFor = (
         newIndex = oldIndex,
       ) => {
         if (
-          newItem !== block.item ||
+          newItem !== block.s[0] ||
           newIndex !== oldIndex ||
           !isReactive(newItem)
         ) {