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:12 -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 { useNavigate } from "react-router-dom";
import { import {
Radio, Radio,
@@ -75,7 +75,7 @@ function getMessagePreview(particle: Particle): string {
} }
} }
function StreamRow({ const StreamRow = memo(function StreamRow({
particle, particle,
networkId, networkId,
onClick, onClick,
@@ -234,7 +234,7 @@ function StreamRow({
)} )}
</div> </div>
); );
} });
interface ParticleListViewProps { interface ParticleListViewProps {
streams: StreamParticle[]; streams: StreamParticle[];
@@ -248,6 +248,13 @@ interface ParticleListViewProps {
*/ */
export function ParticleListView({ streams, networkId, isLoading, selectedIndex }: ParticleListViewProps) { export function ParticleListView({ streams, networkId, isLoading, selectedIndex }: ParticleListViewProps) {
const navigate = useNavigate(); 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) { if (isLoading) {
return <Progress />; return <Progress />;
@@ -269,7 +276,7 @@ export function ParticleListView({ streams, networkId, isLoading, selectedIndex
{streams.map((stream, index) => ( {streams.map((stream, index) => (
<StreamContextMenu key={stream.id} particle={stream} networkId={networkId}> <StreamContextMenu key={stream.id} particle={stream} networkId={networkId}>
<div <div
ref={index === selectedIndex ? (el) => el?.scrollIntoView({ block: "nearest" }) : undefined} ref={(el) => { rowRefs.current[index] = el; }}
> >
<StreamRow <StreamRow
particle={stream} particle={stream}
+7 -2
View File
@@ -13,9 +13,14 @@ export function useStreamKeyboardNav({
}: UseStreamKeyboardNavOptions) { }: UseStreamKeyboardNavOptions) {
const [selectedIndex, setSelectedIndex] = useState<number | null>(null); 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(() => { useEffect(() => {
setSelectedIndex(streams.length > 0 ? 0 : null); setSelectedIndex((prev) => {
if (streams.length === 0) return null;
if (prev === null) return 0;
return prev;
});
}, [streams.length]); }, [streams.length]);
useEffect(() => { useEffect(() => {