瀏覽代碼

feat(runtime-core): support dynamic / external array in v-memo (#4255)

lidlanca 4 年之前
父節點
當前提交
6779bff537

+ 41 - 0
packages/runtime-core/__tests__/helpers/withMemo.spec.ts

@@ -10,6 +10,47 @@ describe('v-memo', () => {
     return [el, vm]
   }
 
+  test('on with external array', async () => {
+    const [el, vm] = mount({
+      template: `<div v-memo="arr">{{ arr[0] }} {{ arr[1] }} {{arr[2] ?? '_' }} ({{c}})</div>{{c}}`,
+      data: () => ({ arr: [0, 0], c: 0 })
+    })
+    expect(el.innerHTML).toBe(`<div>0 0 _ (0)</div>0`)
+
+    let [x, y, z] = [0, 1, 2]
+
+    // change at index x - should update
+    vm.arr[x]++
+    vm.c++
+    await nextTick()
+    expect(el.innerHTML).toBe(`<div>1 0 _ (1)</div>1`)
+
+    // change at index y - should update
+    vm.arr[y]++
+    vm.c++
+    await nextTick()
+    expect(el.innerHTML).toBe(`<div>1 1 _ (2)</div>2`)
+
+    // noop change - should NOT update
+    vm.arr[x] = vm.arr[0]
+    vm.arr[y] = vm.arr[1]
+    vm.c++
+    await nextTick()
+    expect(el.innerHTML).toBe(`<div>1 1 _ (2)</div>3`)
+
+    // add item  3rd item - should update
+    vm.arr[z] = 0
+    vm.c++
+    await nextTick()
+    expect(el.innerHTML).toBe(`<div>1 1 0 (4)</div>4`)
+
+    // remove 3rd item - should update
+    vm.arr = vm.arr.slice(0, vm.arr.length - 1)
+    vm.c++
+    await nextTick()
+    expect(el.innerHTML).toBe(`<div>1 1 _ (5)</div>5`)
+  })
+
   test('on normal element', async () => {
     const [el, vm] = mount({
       template: `<div v-memo="[x]">{{ x }} {{ y }}</div>`,

+ 6 - 1
packages/runtime-core/src/helpers/withMemo.ts

@@ -11,12 +11,17 @@ export function withMemo(
     return cached
   }
   const ret = render()
-  ret.memo = memo
+
+  // shallow clone
+  ret.memo = memo.slice()
   return (cache[index] = ret)
 }
 
 export function isMemoSame(cached: VNode, memo: any[]) {
   const prev: any[] = cached.memo!
+  if (prev.length != memo.length) {
+    return false
+  }
   for (let i = 0; i < prev.length; i++) {
     if (prev[i] !== memo[i]) {
       return false