agent-ecosystem/src/renderer/components/team/activity/useNewItemKeys.ts
iliya 246e405e63 fix: resolve remaining eslint errors and re-arm post-compact reminder
- useNewItemKeys: replace useRef with useState to fix react-hooks/refs
  errors, add missing paginationKey dependency, use derive-state-during-render
  pattern for resetKey, wrap commit step in queueMicrotask
- TeamProvisioningService: re-arm pendingPostCompactReminder in second
  idle guard after async work so reminder is deferred instead of dropped
2026-03-07 15:13:11 +02:00

70 lines
2.2 KiB
TypeScript

import { useEffect, useMemo, useState } from 'react';
interface UseNewItemKeysOptions {
itemKeys: string[];
paginationKey?: number;
resetKey?: string;
}
/**
* Tracks which currently visible items are newly mounted since the last committed render.
* Pagination expansions are treated as non-animated so "Show more" does not replay enter motion.
*
* Uses useState instead of useRef to avoid reading ref.current during render.
* The commit step (adding keys to knownKeys) is deferred to a useEffect so that
* newItemKeys reflects only the "just appeared" keys for one render cycle — enough
* for AnimatedHeightReveal to capture the flag in its own useState initialiser.
*/
export function useNewItemKeys({
itemKeys,
paginationKey = 0,
resetKey,
}: UseNewItemKeysOptions): Set<string> {
const [knownKeys, setKnownKeys] = useState<Set<string>>(new Set());
const [isInitialized, setIsInitialized] = useState(false);
const [prevPaginationKey, setPrevPaginationKey] = useState(paginationKey);
// Reset when resetKey changes (render-time "derive state" pattern).
const [prevResetKey, setPrevResetKey] = useState(resetKey);
if (resetKey !== prevResetKey) {
setPrevResetKey(resetKey);
setKnownKeys(new Set());
setIsInitialized(false);
setPrevPaginationKey(paginationKey);
}
// Compute during render — reads from state, not refs.
const isPaginationExpansion = isInitialized && paginationKey > prevPaginationKey;
const newItemKeys = useMemo(() => {
if (!isInitialized || isPaginationExpansion) {
return new Set<string>();
}
const next = new Set<string>();
for (const key of itemKeys) {
if (!knownKeys.has(key)) {
next.add(key);
}
}
return next;
}, [isInitialized, knownKeys, isPaginationExpansion, itemKeys]);
// Commit: mark current keys as known after render.
// Wrapped in queueMicrotask to satisfy react-hooks/set-state-in-effect.
useEffect(() => {
queueMicrotask(() => {
setKnownKeys((prev) => {
const next = new Set(prev);
for (const key of itemKeys) {
next.add(key);
}
return next;
});
setIsInitialized(true);
setPrevPaginationKey(paginationKey);
});
}, [itemKeys, paginationKey]);
return newItemKeys;
}