fix: prevent unnecessary refetches in webapp dashboard and review pages

Use primitive currentOrgId instead of currentOrg object in React dependency arrays to avoid refetches on reference changes. Guard dashboard fetch behind loadingViewMode. Prevent same-route sidebar navigation from triggering page reloads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
HeshamHM28 2026-04-06 18:12:05 +02:00
parent ea23cf06a6
commit f9aeeca573
3 changed files with 30 additions and 20 deletions

View file

@ -227,6 +227,7 @@ export default function StagingPage() {
const [error, setError] = useState<string | null>(null)
const { currentOrg, loading: isLoadingViewMode } = useViewMode()
const currentOrgId = currentOrg?.id ?? null
const [availableRepositories, setAvailableRepositories] = useState<
Array<{ id: string; full_name: string }>
@ -271,8 +272,6 @@ export default function StagingPage() {
// Reset repository filter immediately when switching contexts (synchronously, before other effects)
useLayoutEffect(() => {
const currentOrgId = currentOrg?.id ?? null
// Skip on initial mount
if (previousOrgId.current === undefined) {
previousOrgId.current = currentOrgId
@ -294,7 +293,7 @@ export default function StagingPage() {
previousOrgId.current = currentOrgId
}
}, [currentOrg])
}, [currentOrgId])
// Load repositories with staging events
useEffect(() => {
@ -303,8 +302,8 @@ export default function StagingPage() {
try {
const userSession = await getUserIdAndUsername()
const repos = await getRepositoriesWithStagingEvents(
currentOrg
? { orgId: currentOrg.id }
currentOrgId
? { orgId: currentOrgId }
: { userId: userSession.userId, username: userSession.username },
)
setAvailableRepositories(repos)
@ -316,7 +315,7 @@ export default function StagingPage() {
if (!isLoadingUser && !isLoadingViewMode && userId) {
loadRepositories()
}
}, [userId, isLoadingUser, isLoadingViewMode, currentOrg])
}, [userId, isLoadingUser, isLoadingViewMode, currentOrgId])
// Memoized load events function
const loadEvents = useCallback(async () => {
@ -364,8 +363,8 @@ export default function StagingPage() {
const userSession = await getUserIdAndUsername()
const data = await getAllOptimizationEvents({
payload: currentOrg
? { orgId: currentOrg.id }
payload: currentOrgId
? { orgId: currentOrgId }
: { userId: userSession.userId, username: userSession.username },
search: filters.search,
filter,
@ -398,7 +397,7 @@ export default function StagingPage() {
} finally {
setIsLoading(false)
}
}, [userId, filters, currentOrg, pageSize])
}, [userId, filters, currentOrgId, pageSize])
// Load events when filters change - with debounce for search
useEffect(() => {

View file

@ -61,7 +61,7 @@ interface ActiveUserData {
}
function Dashboard() {
const { currentOrg } = useViewMode()
const { currentOrg, loading: loadingViewMode } = useViewMode()
const currentYear = new Date().getFullYear()
const [repositories, setRepositories] = useState<RepositoryWithUsage[]>([])
@ -207,8 +207,10 @@ function Dashboard() {
}, [selectedYear, currentOrgId])
useEffect(() => {
if (!loadingViewMode) {
fetchDashboardData()
}, [fetchDashboardData])
}
}, [fetchDashboardData, loadingViewMode])
const handleYearChange = useCallback((year: number) => {
setSelectedYear(year)

View file

@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"
import LogoBox from "@/components/dashboard/logo-box"
import Link from "next/link"
import { usePathname } from "next/navigation"
import React, { useEffect, useState, useRef, type JSX } from "react"
import React, { useEffect, useState, useRef, useCallback, type JSX, type MouseEvent } from "react"
import Image from "next/image"
import {
FolderGit2,
@ -74,6 +74,15 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
const isMemberOfOrg = mode === "organization" && !!currentOrg
const preventSameRouteNavigation = useCallback(
(href: string) => (e: MouseEvent) => {
if (currentRoute === href) {
e.preventDefault()
}
},
[currentRoute],
)
useEffect(() => {
const savedTheme = localStorage.getItem("theme")
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches
@ -243,7 +252,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
<div className="flex-1 overflow-y-auto">
<div className="px-3 py-4">
{/* Main Navigation Group - Always visible */}
<Link href="/dashboard" className="block mb-1">
<Link href="/dashboard" className="block mb-1" onClick={preventSameRouteNavigation("/dashboard")}>
<Button
variant={currentRoute === "/dashboard" ? "secondary" : "ghost"}
className="flex items-center justify-start w-full"
@ -253,7 +262,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
</Button>
</Link>
<Link href="/review-optimizations" className="block mb-1">
<Link href="/review-optimizations" className="block mb-1" onClick={preventSameRouteNavigation("/review-optimizations")}>
<Button
variant={currentRoute === "/review-optimizations" ? "secondary" : "ghost"}
className="flex items-center justify-start w-full"
@ -264,7 +273,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
</Link>
{/* Show full navigation for personal mode or admin/owner in org mode */}
<Link href="/repositories" className="block mb-1">
<Link href="/repositories" className="block mb-1" onClick={preventSameRouteNavigation("/repositories")}>
<Button
variant={currentRoute === "/repositories" ? "secondary" : "ghost"}
className="flex items-center justify-start w-full"
@ -276,7 +285,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
{/* Members tab - only for org members */}
{isMemberOfOrg && (
<Link href="/members" className="block mb-1">
<Link href="/members" className="block mb-1" onClick={preventSameRouteNavigation("/members")}>
<Button
variant={currentRoute === "/members" ? "secondary" : "ghost"}
className="flex items-center justify-start w-full"
@ -323,7 +332,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
</div>
{/* Configuration Group */}
<Link href="/getting-started" className="block mb-1">
<Link href="/getting-started" className="block mb-1" onClick={preventSameRouteNavigation("/getting-started")}>
<Button
variant={currentRoute === "/getting-started" ? "secondary" : "ghost"}
className="flex items-center justify-start w-full"
@ -345,7 +354,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
<div className="h-px bg-border" />
</div>
<Link href="/apikeys" className="block mb-1">
<Link href="/apikeys" className="block mb-1" onClick={preventSameRouteNavigation("/apikeys")}>
<Button
variant={currentRoute === "/apikeys" ? "secondary" : "ghost"}
className="flex items-center justify-start w-full"
@ -357,7 +366,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
{/* Billing - Only for Personal Account */}
{mode === "personal" && (
<Link href="/billing" className="block mb-1">
<Link href="/billing" className="block mb-1" onClick={preventSameRouteNavigation("/billing")}>
<Button
variant={currentRoute === "/billing" ? "secondary" : "ghost"}
className="flex items-center justify-start w-full"