Skip to content

Commit e26d408

Browse files
committed
fix(fe): implement syncUpdateChildrenProps and enhance triggerObserver method to skip duplicate observer execution
1 parent a86f257 commit e26d408

4 files changed

Lines changed: 118 additions & 20 deletions

File tree

fe/packages/service/__tests__/component-observer-order.spec.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ describe('Component.tO observer ordering', () => {
1010
position: 'center',
1111
name: 'fade',
1212
},
13+
__pendingSyncedProps__: {},
1314
__info__: {
1415
observers: {
1516
'show': () => {
@@ -45,4 +46,33 @@ describe('Component.tO observer ordering', () => {
4546
'observeShow:top',
4647
])
4748
})
49+
50+
it('skips duplicate observer execution for identical render replay after parent sync', () => {
51+
const observeShow = vi.fn()
52+
const instance = {
53+
data: {
54+
show: true,
55+
},
56+
__pendingSyncedProps__: {
57+
show: true,
58+
},
59+
__info__: {
60+
observers: {},
61+
properties: {
62+
show: {
63+
observer: 'observeShow',
64+
},
65+
},
66+
},
67+
observeShow,
68+
}
69+
70+
Component.prototype.tO.call(instance, {
71+
show: true,
72+
})
73+
74+
expect(observeShow).not.toHaveBeenCalled()
75+
expect(instance.__pendingSyncedProps__).toEqual({})
76+
expect(instance.data.show).toBe(true)
77+
})
4878
})

fe/packages/service/__tests__/utils.spec.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it, vi } from 'vitest'
2-
import { filterInvokeObserver, mergeBehaviors } from '../src/core/utils'
2+
import { filterInvokeObserver, mergeBehaviors, syncUpdateChildrenProps } from '../src/core/utils'
33

44
describe('数据监听器触发匹配逻辑', () => {
55
const funAB = vi.fn((numberA, numberB) => {
@@ -429,3 +429,53 @@ describe('观察者函数 oldVal 参数测试', () => {
429429
expect(observer).not.toHaveBeenCalledWith(10, 20, 5)
430430
})
431431
})
432+
433+
describe('syncUpdateChildrenProps', () => {
434+
it('triggers child property observers during parent setData sync', () => {
435+
const child = {
436+
__id__: 'child-1',
437+
__parentId__: 'parent-1',
438+
__pendingSyncedProps__: {},
439+
__info__: {
440+
properties: {
441+
show: {},
442+
name: {},
443+
},
444+
},
445+
tO: vi.fn(),
446+
}
447+
const parent = {
448+
__id__: 'parent-1',
449+
data: {
450+
show: true,
451+
name: 'fade',
452+
},
453+
__childPropsBindings__: {
454+
'child-1': {
455+
show: {
456+
expression: 'show',
457+
dependencies: ['show'],
458+
isSimple: true,
459+
},
460+
name: {
461+
expression: 'name',
462+
dependencies: ['name'],
463+
isSimple: true,
464+
},
465+
},
466+
},
467+
}
468+
469+
syncUpdateChildrenProps(parent, {
470+
'child-1': child,
471+
}, {
472+
show: true,
473+
name: 'fade',
474+
})
475+
476+
expect(child.tO).toHaveBeenCalledWith({
477+
show: true,
478+
name: 'fade',
479+
})
480+
})
481+
})

fe/packages/service/src/core/utils.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,9 +700,11 @@ export function syncUpdateChildrenProps(parent, allInstances, changedData) {
700700
}
701701
}
702702

703-
// 如果有数据需要更新,触发子组件的 tO 方法,但不触发 observers
703+
// 如果有数据需要更新,直接触发子组件 observers,确保属性驱动的行为在 service 侧即时生效
704704
if (Object.keys(updateData).length > 0) {
705-
child.tO?.(updateData, false)
705+
child.__pendingSyncedProps__ = child.__pendingSyncedProps__ || {}
706+
Object.assign(child.__pendingSyncedProps__, updateData)
707+
child.tO?.(updateData)
706708
}
707709
}
708710
}

fe/packages/service/src/instance/component/component.js

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createSelectorQuery } from '../../api/core/wxml/selector-query'
33
import { createIntersectionObserver } from '../../api/core/wxml/intersection-observer'
44
import message from '../../core/message'
55
import runtime from '../../core/runtime'
6-
import { addComputedData, filterData, filterInvokeObserver, invokeObserversOnce, isChildComponent, matchComponent, syncUpdateChildrenProps } from '../../core/utils'
6+
import { addComputedData, deepEqual, filterData, filterInvokeObserver, invokeObserversOnce, isChildComponent, matchComponent, syncUpdateChildrenProps } from '../../core/utils'
77

88
// 组件生命周期
99
const componentLifetimes = ['created', 'attached', 'ready', 'moved', 'detached', 'error']
@@ -60,6 +60,7 @@ export class Component {
6060
// 保存子组件 properties 绑定关系(用于同步更新)
6161
// 格式:{ childModuleId: { childPropName: parentDataKey } }
6262
this.__childPropsBindings__ = {}
63+
this.__pendingSyncedProps__ = {}
6364
}
6465

6566
init() {
@@ -461,33 +462,48 @@ export class Component {
461462
* 触发观察者函数
462463
* triggerObserver
463464
*/
464-
tO(data, triggerObservers = true) {
465+
tO(data) {
466+
const nextData = {}
467+
for (const [prop, val] of Object.entries(data)) {
468+
if (
469+
this.__pendingSyncedProps__
470+
&& Object.hasOwn(this.__pendingSyncedProps__, prop)
471+
&& deepEqual(this.__pendingSyncedProps__[prop], val)
472+
) {
473+
delete this.__pendingSyncedProps__[prop]
474+
continue
475+
}
476+
nextData[prop] = val
477+
}
478+
479+
if (Object.keys(nextData).length === 0) {
480+
return
481+
}
482+
465483
// 收集需要执行的观察者函数
466484
const observersToExecute = []
467485
const propertyObserversToExecute = []
468486

469487
// 保存旧值并更新数据,收集观察者
470-
for (const [prop, val] of Object.entries(data)) {
488+
for (const [prop, val] of Object.entries(nextData)) {
471489
// 保存旧值
472490
const oldVal = this.data[prop]
473491

474492
// 更新数据
475493
this.data[prop] = val
476494

477-
if (triggerObservers) {
478-
// 收集 observers
479-
if (this.__info__.observers) {
480-
observersToExecute.push(() => filterInvokeObserver(prop, this.__info__.observers, data, this, oldVal))
481-
}
482-
483-
// 收集属性观察器
484-
const observer = this.__info__.properties?.[prop]?.observer
485-
if (isString(observer)) {
486-
propertyObserversToExecute.push(() => this[observer]?.(val, oldVal))
487-
}
488-
else if (isFunction(observer)) {
489-
propertyObserversToExecute.push(() => observer.call(this, val, oldVal))
490-
}
495+
// 收集 observers
496+
if (this.__info__.observers) {
497+
observersToExecute.push(() => filterInvokeObserver(prop, this.__info__.observers, this.data, this, oldVal))
498+
}
499+
500+
// 收集属性观察器
501+
const observer = this.__info__.properties?.[prop]?.observer
502+
if (isString(observer)) {
503+
propertyObserversToExecute.push(() => this[observer]?.(val, oldVal))
504+
}
505+
else if (isFunction(observer)) {
506+
propertyObserversToExecute.push(() => observer.call(this, val, oldVal))
491507
}
492508
}
493509

0 commit comments

Comments
 (0)