Skip to content

Commit dbc0e4a

Browse files
yyx990803aJean
authored andcommitted
fix: beforeUpdate should be called before render and allow state mutation (vuejs#7822)
fix vuejs#7481
1 parent 3e1a188 commit dbc0e4a

File tree

5 files changed

+42
-15
lines changed

5 files changed

+42
-15
lines changed

src/core/instance/lifecycle.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ export function initLifecycle (vm: Component) {
5050
export function lifecycleMixin (Vue: Class<Component>) {
5151
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
5252
const vm: Component = this
53-
if (vm._isMounted) {
54-
callHook(vm, 'beforeUpdate')
55-
}
5653
const prevEl = vm.$el
5754
const prevVnode = vm._vnode
5855
const prevActiveInstance = activeInstance
@@ -197,7 +194,13 @@ export function mountComponent (
197194
// we set this to vm._watcher inside the watcher's constructor
198195
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
199196
// component's mounted hook), which relies on vm._watcher being already defined
200-
new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)
197+
new Watcher(vm, updateComponent, noop, {
198+
before () {
199+
if (vm._isMounted) {
200+
callHook(vm, 'beforeUpdate')
201+
}
202+
}
203+
}, true /* isRenderWatcher */)
201204
hydrating = false
202205

203206
// manually mounted instance, call mounted on self

src/core/observer/scheduler.js

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ function flushSchedulerQueue () {
5353
// as we run existing watchers
5454
for (index = 0; index < queue.length; index++) {
5555
watcher = queue[index]
56+
if (watcher.before) {
57+
watcher.before()
58+
}
5659
id = watcher.id
5760
has[id] = null
5861
watcher.run()

src/core/observer/watcher.js

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default class Watcher {
3737
newDeps: Array<Dep>;
3838
depIds: SimpleSet;
3939
newDepIds: SimpleSet;
40+
before: ?Function;
4041
getter: Function;
4142
value: any;
4243

@@ -58,6 +59,7 @@ export default class Watcher {
5859
this.user = !!options.user
5960
this.lazy = !!options.lazy
6061
this.sync = !!options.sync
62+
this.before = options.before
6163
} else {
6264
this.deep = this.user = this.lazy = this.sync = false
6365
}

src/platforms/web/runtime/components/transition-group.js

+15-11
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ delete props.mode
3333
export default {
3434
props,
3535

36+
beforeMount () {
37+
const update = this._update
38+
this._update = (vnode, hydrating) => {
39+
// force removing pass
40+
this.__patch__(
41+
this._vnode,
42+
this.kept,
43+
false, // hydrating
44+
true // removeOnly (!important, avoids unnecessary moves)
45+
)
46+
this._vnode = this.kept
47+
update.call(this, vnode, hydrating)
48+
}
49+
},
50+
3651
render (h: Function) {
3752
const tag: string = this.tag || this.$vnode.data.tag || 'span'
3853
const map: Object = Object.create(null)
@@ -76,17 +91,6 @@ export default {
7691
return h(tag, null, children)
7792
},
7893

79-
beforeUpdate () {
80-
// force removing pass
81-
this.__patch__(
82-
this._vnode,
83-
this.kept,
84-
false, // hydrating
85-
true // removeOnly (!important, avoids unnecessary moves)
86-
)
87-
this._vnode = this.kept
88-
},
89-
9094
updated () {
9195
const children: Array<VNode> = this.prevChildren
9296
const moveClass: string = this.moveClass || ((this.name || 'v') + '-move')

test/unit/features/options/lifecycle.spec.js

+15
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,21 @@ describe('Options lifecycle hooks', () => {
137137
expect(spy).toHaveBeenCalled()
138138
}).then(done)
139139
})
140+
141+
it('should be called before render and allow mutating state', done => {
142+
const vm = new Vue({
143+
template: '<div>{{ msg }}</div>',
144+
data: { msg: 'foo' },
145+
beforeUpdate () {
146+
this.msg += '!'
147+
}
148+
}).$mount()
149+
expect(vm.$el.textContent).toBe('foo')
150+
vm.msg = 'bar'
151+
waitForUpdate(() => {
152+
expect(vm.$el.textContent).toBe('bar!')
153+
}).then(done)
154+
})
140155
})
141156

142157
describe('updated', () => {

0 commit comments

Comments
 (0)