Context
In packages/libs/sdk-mixins/src/mixins/createStateManagementMixin.ts, the subscribe method invokes the consumer callback on every store change:
this.subscribe = (cb, selector = (state) => state as any) =>
store.subscribe(() => cb(selector(store.getState())));
As a result, every call site that only wants to react when the selected slice actually changes has to wrap its own callback with withMemCache from @descope/sdk-helpers. This pattern is repeated across many widget mixins, for example:
packages/widgets/audit-management-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initAuditTableMixin.ts
packages/widgets/user-profile-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initUserBuiltinAttributesMixin.ts
packages/widgets/user-profile-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initNotificationsMixin.ts
packages/widgets/user-profile-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initEmailUserAttrMixin.ts
- ... and many more under
packages/widgets/**/initComponentsMixins/
Typical pattern at each call site:
#onAuditListUpdate = withMemCache((auditList) => { ... });
// ...
this.subscribe(this.#onAuditListUpdate.bind(this), getAuditList);
Proposal
Move the withMemCache wrapping inside subscribe itself, so the callback only fires when the selector's output actually changes:
this.subscribe = (cb, selector = (state) => state as any) => {
const memoized = withMemCache(cb);
return store.subscribe(() => memoized(selector(store.getState())));
};
Then remove the redundant withMemCache(...) wrappers from every subscribe call site across the widgets.
Benefits
- Removes duplicated boilerplate across all widget mixins.
- Centralizes the change-detection behavior — easier to reason about and harder to forget.
- Reduces the surface area for bugs where someone forgets to wrap their callback and triggers unnecessary re-renders/DOM work.
Scope
- Update
createStateManagementMixin.ts to wrap cb with withMemCache.
- Audit all
.subscribe( callers in packages/widgets/** (and elsewhere) and drop the now-redundant withMemCache wrapping.
- Verify no caller relies on the callback firing on every store change regardless of selector output.
Context
In
packages/libs/sdk-mixins/src/mixins/createStateManagementMixin.ts, thesubscribemethod invokes the consumer callback on every store change:As a result, every call site that only wants to react when the selected slice actually changes has to wrap its own callback with
withMemCachefrom@descope/sdk-helpers. This pattern is repeated across many widget mixins, for example:packages/widgets/audit-management-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initAuditTableMixin.tspackages/widgets/user-profile-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initUserBuiltinAttributesMixin.tspackages/widgets/user-profile-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initNotificationsMixin.tspackages/widgets/user-profile-widget/src/lib/widget/mixins/initMixin/initComponentsMixins/initEmailUserAttrMixin.tspackages/widgets/**/initComponentsMixins/Typical pattern at each call site:
Proposal
Move the
withMemCachewrapping insidesubscribeitself, so the callback only fires when the selector's output actually changes:Then remove the redundant
withMemCache(...)wrappers from everysubscribecall site across the widgets.Benefits
Scope
createStateManagementMixin.tsto wrapcbwithwithMemCache..subscribe(callers inpackages/widgets/**(and elsewhere) and drop the now-redundantwithMemCachewrapping.