Skip to content

Commit 215a4c8

Browse files
committed
Reduce recalculations when unrelated state changes
1 parent 967e88e commit 215a4c8

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

frontend/src/routes/(root)/(logged)/tutorials/+page.svelte

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,40 @@
5050
})
5151
5252
53+
// Memoize access check dependencies to avoid unnecessary recalculations
54+
// This derived value only recalculates when userStore or selectedPreviewRole changes
55+
const accessCheckContext = $derived.by(() => {
56+
const user = $userStore
57+
const usePreview = user?.is_admin && selectedPreviewRole !== userEffectiveRole
58+
return { user, usePreview, previewRole: selectedPreviewRole }
59+
})
60+
5361
/**
5462
* Check if the current user (or preview role) has access to a roles array.
5563
* Handles both normal access and admin preview mode.
5664
*/
5765
function checkAccess(roles?: Role[]): boolean {
58-
const user = $userStore
66+
const context = accessCheckContext
5967
// Use preview function if admin has selected a different role to preview
60-
if (user?.is_admin && selectedPreviewRole !== userEffectiveRole) {
61-
return hasRoleAccessForPreview(selectedPreviewRole, roles)
68+
if (context.usePreview) {
69+
return hasRoleAccessForPreview(context.previewRole, roles)
6270
}
63-
return hasRoleAccess(user, roles)
71+
return hasRoleAccess(context.user, roles)
6472
}
6573
6674
// Get active tabs only (filtered by active and roles)
75+
// Optimized: $derived.by() automatically memoizes - only recalculates when dependencies change
6776
const activeTabs = $derived.by(() => {
77+
// Access context to establish reactive dependency
78+
const context = accessCheckContext
6879
return (Object.entries(TUTORIALS_CONFIG) as [TabId, TabConfig][]).filter(([, config]) => {
6980
// Filter by active
7081
if (config.active === false) return false
71-
// Filter by roles
72-
return checkAccess(config.roles)
82+
// Filter by roles (context is captured in closure)
83+
if (context.usePreview) {
84+
return hasRoleAccessForPreview(context.previewRole, config.roles)
85+
}
86+
return hasRoleAccess(context.user, config.roles)
7387
})
7488
})
7589
@@ -91,21 +105,29 @@
91105
const currentTabConfig = $derived(TUTORIALS_CONFIG[tab])
92106
93107
// Filter tutorials by role and active status (same logic as displayed tutorials)
94-
const visibleTutorials = $derived(
95-
currentTabConfig.tutorials.filter((tutorial) => {
108+
// Optimized: $derived.by() automatically memoizes - only recalculates when tab or accessCheckContext changes
109+
const visibleTutorials = $derived.by(() => {
110+
// Access context to establish reactive dependency
111+
const context = accessCheckContext
112+
return currentTabConfig.tutorials.filter((tutorial) => {
96113
if (tutorial.active === false) return false
97-
return checkAccess(tutorial.roles)
114+
// Use context directly to avoid function call overhead
115+
if (context.usePreview) {
116+
return hasRoleAccessForPreview(context.previewRole, tutorial.roles)
117+
}
118+
return hasRoleAccess(context.user, tutorial.roles)
98119
})
99-
)
120+
})
100121
101122
// Create tutorial index mapping for current tab (only visible tutorials with index defined)
102-
const currentTabTutorialIndexes = $derived(
103-
Object.fromEntries(
123+
// Optimized: only recalculates when visibleTutorials changes
124+
const currentTabTutorialIndexes = $derived.by(() => {
125+
return Object.fromEntries(
104126
visibleTutorials
105127
.filter((tutorial) => tutorial.index !== undefined)
106128
.map((tutorial) => [tutorial.id, tutorial.index!])
107129
)
108-
)
130+
})
109131
110132
// Calculate progress for current tab (only counting visible tutorials)
111133
const totalTutorials = $derived(getTutorialProgressTotal(currentTabTutorialIndexes))

0 commit comments

Comments
 (0)