The TypeScript check passed with no errors. The debounce pattern from VirtualizedProcessLogs.tsx has been successfully rolled out to ConversationList.tsx. (#1909)
## Summary Added 100ms debounce to `ConversationList.tsx` matching the pattern in `VirtualizedProcessLogs.tsx`: 1. **Added refs** (lines 94-99): `pendingUpdateRef` to store pending updates and `debounceTimeoutRef` to track the timeout 2. **Modified `onEntriesUpdated`** (lines 115-149): Now stores updates in the ref and debounces state updates with a 100ms delay 3. **Added cleanup effect** (lines 107-113): Clears any pending timeout on unmount to prevent memory leaks
This commit is contained in:
committed by
GitHub
parent
a92c35d42e
commit
e2fad0e10c
@@ -91,6 +91,12 @@ export function ConversationList({ attempt, task }: ConversationListProps) {
|
|||||||
useState<DataWithScrollModifier<PatchTypeWithKey> | null>(null);
|
useState<DataWithScrollModifier<PatchTypeWithKey> | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const { setEntries, reset } = useEntries();
|
const { setEntries, reset } = useEntries();
|
||||||
|
const pendingUpdateRef = useRef<{
|
||||||
|
entries: PatchTypeWithKey[];
|
||||||
|
addType: AddEntryType;
|
||||||
|
loading: boolean;
|
||||||
|
} | null>(null);
|
||||||
|
const debounceTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -98,25 +104,48 @@ export function ConversationList({ attempt, task }: ConversationListProps) {
|
|||||||
reset();
|
reset();
|
||||||
}, [attempt.id, reset]);
|
}, [attempt.id, reset]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (debounceTimeoutRef.current) {
|
||||||
|
clearTimeout(debounceTimeoutRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const onEntriesUpdated = (
|
const onEntriesUpdated = (
|
||||||
newEntries: PatchTypeWithKey[],
|
newEntries: PatchTypeWithKey[],
|
||||||
addType: AddEntryType,
|
addType: AddEntryType,
|
||||||
newLoading: boolean
|
newLoading: boolean
|
||||||
) => {
|
) => {
|
||||||
let scrollModifier: ScrollModifier = InitialDataScrollModifier;
|
pendingUpdateRef.current = {
|
||||||
|
entries: newEntries,
|
||||||
|
addType,
|
||||||
|
loading: newLoading,
|
||||||
|
};
|
||||||
|
|
||||||
if (addType === 'plan' && !loading) {
|
if (debounceTimeoutRef.current) {
|
||||||
scrollModifier = ScrollToTopOfLastItem;
|
clearTimeout(debounceTimeoutRef.current);
|
||||||
} else if (addType === 'running' && !loading) {
|
|
||||||
scrollModifier = AutoScrollToBottom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setChannelData({ data: newEntries, scrollModifier });
|
debounceTimeoutRef.current = setTimeout(() => {
|
||||||
setEntries(newEntries);
|
const pending = pendingUpdateRef.current;
|
||||||
|
if (!pending) return;
|
||||||
|
|
||||||
if (loading) {
|
let scrollModifier: ScrollModifier = InitialDataScrollModifier;
|
||||||
setLoading(newLoading);
|
|
||||||
}
|
if (pending.addType === 'plan' && !loading) {
|
||||||
|
scrollModifier = ScrollToTopOfLastItem;
|
||||||
|
} else if (pending.addType === 'running' && !loading) {
|
||||||
|
scrollModifier = AutoScrollToBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
setChannelData({ data: pending.entries, scrollModifier });
|
||||||
|
setEntries(pending.entries);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
setLoading(pending.loading);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
useConversationHistory({ attempt, onEntriesUpdated });
|
useConversationHistory({ attempt, onEntriesUpdated });
|
||||||
|
|||||||
Reference in New Issue
Block a user