]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): fix beforeUpdate call timing to allow state mutation
authorEvan You <yyx990803@gmail.com>
Wed, 19 Aug 2020 21:57:51 +0000 (17:57 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 19 Aug 2020 21:57:51 +0000 (17:57 -0400)
fix #1899

packages/runtime-core/__tests__/apiLifecycle.spec.ts
packages/runtime-core/src/renderer.ts

index 003a3d0a8dde7ea9f1c7cdecc7f6f74ba8f9f80c..a4c89ff95cba52c777f820a9475b6acd38a88001 100644 (file)
@@ -74,6 +74,36 @@ describe('api: lifecycle hooks', () => {
     count.value++
     await nextTick()
     expect(fn).toHaveBeenCalledTimes(1)
+    expect(serializeInner(root)).toBe(`<div>1</div>`)
+  })
+
+  it('state mutation in onBeforeUpdate', async () => {
+    const count = ref(0)
+    const root = nodeOps.createElement('div')
+    const fn = jest.fn(() => {
+      // should be called before inner div is updated
+      expect(serializeInner(root)).toBe(`<div>0</div>`)
+      count.value++
+    })
+    const renderSpy = jest.fn()
+
+    const Comp = {
+      setup() {
+        onBeforeUpdate(fn)
+        return () => {
+          renderSpy()
+          return h('div', count.value)
+        }
+      }
+    }
+    render(h(Comp), root)
+    expect(renderSpy).toHaveBeenCalledTimes(1)
+
+    count.value++
+    await nextTick()
+    expect(fn).toHaveBeenCalledTimes(1)
+    expect(renderSpy).toHaveBeenCalledTimes(2)
+    expect(serializeInner(root)).toBe(`<div>2</div>`)
   })
 
   it('onUpdated', async () => {
index 97e4bf06c3a86353ccb0fdfb8467fc449b46954d..6497e88edcce259f081c89a7e0df2f2b36d965cf 100644 (file)
@@ -1281,13 +1281,7 @@ function baseCreateRenderer(
         let vnodeHook: VNodeHook | null | undefined
         const { el, props } = initialVNode
         const { bm, m, parent } = instance
-        if (__DEV__) {
-          startMeasure(instance, `render`)
-        }
-        const subTree = (instance.subTree = renderComponentRoot(instance))
-        if (__DEV__) {
-          endMeasure(instance, `render`)
-        }
+
         // beforeMount hook
         if (bm) {
           invokeArrayFns(bm)
@@ -1296,6 +1290,16 @@ function baseCreateRenderer(
         if ((vnodeHook = props && props.onVnodeBeforeMount)) {
           invokeVNodeHook(vnodeHook, parent, initialVNode)
         }
+
+        // render
+        if (__DEV__) {
+          startMeasure(instance, `render`)
+        }
+        const subTree = (instance.subTree = renderComponentRoot(instance))
+        if (__DEV__) {
+          endMeasure(instance, `render`)
+        }
+
         if (el && hydrateNode) {
           if (__DEV__) {
             startMeasure(instance, `hydrate`)
@@ -1365,16 +1369,8 @@ function baseCreateRenderer(
         } else {
           next = vnode
         }
-        if (__DEV__) {
-          startMeasure(instance, `render`)
-        }
-        const nextTree = renderComponentRoot(instance)
-        if (__DEV__) {
-          endMeasure(instance, `render`)
-        }
-        const prevTree = instance.subTree
-        instance.subTree = nextTree
         next.el = vnode.el
+
         // beforeUpdate hook
         if (bu) {
           invokeArrayFns(bu)
@@ -1383,6 +1379,18 @@ function baseCreateRenderer(
         if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
           invokeVNodeHook(vnodeHook, parent, next, vnode)
         }
+
+        // render
+        if (__DEV__) {
+          startMeasure(instance, `render`)
+        }
+        const nextTree = renderComponentRoot(instance)
+        if (__DEV__) {
+          endMeasure(instance, `render`)
+        }
+        const prevTree = instance.subTree
+        instance.subTree = nextTree
+
         // reset refs
         // only needed if previous patch had refs
         if (instance.refs !== EMPTY_OBJ) {