Skip to content

Commit ebaac9a

Browse files
committed
perf(reactivity): avoid triggering re-render if computed value did not change
1 parent f5617fc commit ebaac9a

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

packages/reactivity/src/computed.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ReactiveFlags, toRaw } from './reactive'
55

66
export interface ComputedRef<T = any> extends WritableComputedRef<T> {
77
readonly value: T
8+
defer?: (fn: () => void) => void
89
}
910

1011
export interface WritableComputedRef<T> extends Ref<T> {
@@ -19,6 +20,16 @@ export interface WritableComputedOptions<T> {
1920
set: ComputedSetter<T>
2021
}
2122

23+
type ComputedScheduler = (fn: () => void) => void
24+
let scheduler: ComputedScheduler | undefined
25+
26+
/**
27+
* Set a scheduler for deferring computed computations
28+
*/
29+
export const setComputedScheduler = (s: ComputedScheduler | undefined) => {
30+
scheduler = s
31+
}
32+
2233
class ComputedRefImpl<T> {
2334
public dep?: Set<ReactiveEffect> = undefined
2435

@@ -35,10 +46,34 @@ class ComputedRefImpl<T> {
3546
private readonly _setter: ComputedSetter<T>,
3647
isReadonly: boolean
3748
) {
49+
let deferFn: () => void
50+
let scheduled = false
3851
this.effect = new ReactiveEffect(getter, () => {
3952
if (!this._dirty) {
4053
this._dirty = true
41-
triggerRefValue(this)
54+
if (scheduler) {
55+
if (!scheduled) {
56+
scheduled = true
57+
scheduler(
58+
deferFn ||
59+
(deferFn = () => {
60+
scheduled = false
61+
if (this._dirty) {
62+
this._dirty = false
63+
const newValue = this.effect.run()!
64+
if (this._value !== newValue) {
65+
this._value = newValue
66+
triggerRefValue(this)
67+
}
68+
} else {
69+
triggerRefValue(this)
70+
}
71+
})
72+
)
73+
}
74+
} else {
75+
triggerRefValue(this)
76+
}
4277
}
4378
})
4479
this[ReactiveFlags.IS_READONLY] = isReadonly

packages/reactivity/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export {
3030
} from './reactive'
3131
export {
3232
computed,
33+
setComputedScheduler,
3334
ComputedRef,
3435
WritableComputedRef,
3536
WritableComputedOptions,

packages/runtime-core/src/scheduler.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { ErrorCodes, callWithErrorHandling } from './errorHandling'
22
import { isArray } from '@vue/shared'
33
import { ComponentInternalInstance, getComponentName } from './component'
44
import { warn } from './warning'
5+
import { setComputedScheduler } from '@vue/reactivity'
6+
7+
// set scheduler for computed
8+
setComputedScheduler(queueJob)
59

610
export interface SchedulerJob extends Function {
711
id?: number

0 commit comments

Comments
 (0)