fix(github-issues): revert problematic changes from performance optimization
- Reverted createWithEqualityFn changes that caused infinite loop - Removed useRenderCount hook that caused rendering issues - Kept individual store subscriptions (more reliable than shallow) - Kept other optimizations: filtering early-return, investigation useMemos, debounce, task filtering
This commit is contained in:
@@ -44,7 +44,6 @@ import {
|
||||
} from "./ui/alert-dialog";
|
||||
import { useMutationStore } from "../stores/github/mutation-store";
|
||||
import { useToast } from "../hooks/use-toast";
|
||||
import { useRenderCount } from "../hooks/useRenderCount";
|
||||
import type { GitHubIssue, InvestigationState, InvestigationDismissReason, SuggestedLabel } from "../../shared/types";
|
||||
import type { GitHubIssuesProps } from "./github-issues/types";
|
||||
|
||||
@@ -69,9 +68,6 @@ export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesP
|
||||
const { t } = useTranslation("common");
|
||||
const { toast } = useToast();
|
||||
|
||||
// Performance monitoring (dev only) - always call hook, it exits early in prod
|
||||
useRenderCount('GitHubIssues', 5000);
|
||||
|
||||
const projects = useProjectStore((state) => state.projects);
|
||||
const selectedProjectId = useProjectStore((state) => state.selectedProjectId);
|
||||
const selectedProject = projects.find((p) => p.id === selectedProjectId);
|
||||
|
||||
@@ -5,24 +5,18 @@ import {
|
||||
loadGitHubIssues,
|
||||
loadMoreGitHubIssues,
|
||||
checkGitHubConnection,
|
||||
shallow,
|
||||
} from "../../../stores/github";
|
||||
import type { FilterState } from "../types";
|
||||
|
||||
export function useGitHubIssues(projectId: string | undefined) {
|
||||
// Single subscription using shallow comparison
|
||||
const { issues, isLoading, isLoadingMore, error, selectedIssueNumber, filterState, hasMore } = useIssuesStore(
|
||||
(s) => ({
|
||||
issues: s.issues,
|
||||
isLoading: s.isLoading,
|
||||
isLoadingMore: s.isLoadingMore,
|
||||
error: s.error,
|
||||
selectedIssueNumber: s.selectedIssueNumber,
|
||||
filterState: s.filterState,
|
||||
hasMore: s.hasMore,
|
||||
}),
|
||||
shallow
|
||||
);
|
||||
// Individual subscriptions to avoid re-render on unrelated state changes
|
||||
const issues = useIssuesStore((s) => s.issues);
|
||||
const isLoading = useIssuesStore((s) => s.isLoading);
|
||||
const isLoadingMore = useIssuesStore((s) => s.isLoadingMore);
|
||||
const error = useIssuesStore((s) => s.error);
|
||||
const selectedIssueNumber = useIssuesStore((s) => s.selectedIssueNumber);
|
||||
const filterState = useIssuesStore((s) => s.filterState);
|
||||
const hasMore = useIssuesStore((s) => s.hasMore);
|
||||
|
||||
const selectIssue = useIssuesStore((s) => s.selectIssue);
|
||||
const setFilterState = useIssuesStore((s) => s.setFilterState);
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { useRef, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* Hook to track component render count for performance monitoring (dev only).
|
||||
* Usage: useRenderCount('GitHubIssues', 100);
|
||||
*/
|
||||
export function useRenderCount(componentName: string, logInterval = 100) {
|
||||
const renderCount = useRef(0);
|
||||
const lastLogTime = useRef(Date.now());
|
||||
|
||||
// Always increment (minimal overhead)
|
||||
renderCount.current += 1;
|
||||
|
||||
useEffect(() => {
|
||||
// Only log in development
|
||||
if (!import.meta.env.DEV) {
|
||||
return;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const elapsed = now - lastLogTime.current;
|
||||
|
||||
if (elapsed >= logInterval) {
|
||||
console.log(
|
||||
`[Performance] ${componentName} rendered ${renderCount.current} times in ${elapsed}ms ` +
|
||||
`(${Math.round(renderCount.current / (elapsed / 1000))} renders/sec)`
|
||||
);
|
||||
renderCount.current = 0;
|
||||
lastLogTime.current = now;
|
||||
}
|
||||
});
|
||||
|
||||
return renderCount.current;
|
||||
}
|
||||
@@ -51,9 +51,6 @@ export {
|
||||
checkGitHubConnection
|
||||
} from './sync-status-store';
|
||||
|
||||
// Utilities
|
||||
export { shallow } from '../utils';
|
||||
|
||||
/**
|
||||
* Initialize all global GitHub listeners.
|
||||
* Call this once at app startup.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createWithEqualityFn } from 'zustand/traditional';
|
||||
import { create } from 'zustand';
|
||||
import type { GitHubIssue } from '@shared/types';
|
||||
|
||||
export type IssueFilterState = 'open' | 'closed' | 'all';
|
||||
@@ -39,7 +39,7 @@ interface IssuesState {
|
||||
getOpenIssuesCount: () => number;
|
||||
}
|
||||
|
||||
export const useIssuesStore = createWithEqualityFn<IssuesState>((set, get) => ({
|
||||
export const useIssuesStore = create<IssuesState>((set, get) => ({
|
||||
// Initial state
|
||||
issues: [],
|
||||
isLoading: false,
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Shallow comparison function for Zustand selectors.
|
||||
* Returns true if a and b are shallowly equal (same reference or same primitives).
|
||||
*/
|
||||
export function shallow<T>(objA: T, objB: T): boolean {
|
||||
if (Object.is(objA, objB)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof objA !== 'object' ||
|
||||
objA === null ||
|
||||
typeof objB !== 'object' ||
|
||||
objB === null
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const keysA = Object.keys(objA as unknown as object);
|
||||
const keysB = Object.keys(objB as unknown as object);
|
||||
|
||||
if (keysA.length !== keysB.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const key of keysA) {
|
||||
if (
|
||||
!Object.prototype.hasOwnProperty.call(objB, key) ||
|
||||
!Object.is((objA as any)[key], (objB as any)[key])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user