fix: list of streams glitching to top

This was due to real-time changes to items leading to scrolling to top.

Closes #123
This commit is contained in:
talksik
2026-04-08 08:56:04 -07:00
parent 7e11d66dc2
commit 8cbc04fff7
2 changed files with 18 additions and 6 deletions
@@ -1,4 +1,4 @@
import { useMemo } from "react";
import { useMemo, useRef, useEffect, memo } from "react";
import { useNavigate } from "react-router-dom";
import {
Radio,
@@ -75,7 +75,7 @@ function getMessagePreview(particle: Particle): string {
}
}
function StreamRow({
const StreamRow = memo(function StreamRow({
particle,
networkId,
onClick,
@@ -234,7 +234,7 @@ function StreamRow({
)}
</div>
);
}
});
interface ParticleListViewProps {
streams: StreamParticle[];
@@ -248,6 +248,13 @@ interface ParticleListViewProps {
*/
export function ParticleListView({ streams, networkId, isLoading, selectedIndex }: ParticleListViewProps) {
const navigate = useNavigate();
const rowRefs = useRef<(HTMLDivElement | null)[]>([]);
useEffect(() => {
if (selectedIndex !== null && selectedIndex !== undefined && selectedIndex >= 0) {
rowRefs.current[selectedIndex]?.scrollIntoView({ block: "nearest" });
}
}, [selectedIndex]);
if (isLoading) {
return <Progress />;
@@ -269,7 +276,7 @@ export function ParticleListView({ streams, networkId, isLoading, selectedIndex
{streams.map((stream, index) => (
<StreamContextMenu key={stream.id} particle={stream} networkId={networkId}>
<div
ref={index === selectedIndex ? (el) => el?.scrollIntoView({ block: "nearest" }) : undefined}
ref={(el) => { rowRefs.current[index] = el; }}
>
<StreamRow
particle={stream}
+7 -2
View File
@@ -13,9 +13,14 @@ export function useStreamKeyboardNav({
}: UseStreamKeyboardNavOptions) {
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
// Reset selection to first item when streams change or view mode switches
// Initialize selection when streams first load; clear if streams become empty.
// Do NOT reset on every Firestore update — that would scroll the list to the top.
useEffect(() => {
setSelectedIndex(streams.length > 0 ? 0 : null);
setSelectedIndex((prev) => {
if (streams.length === 0) return null;
if (prev === null) return 0;
return prev;
});
}, [streams.length]);
useEffect(() => {