diff --git a/package-lock.json b/package-lock.json index 1d1631d..97115aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "react-medium-image-zoom": "^5.4.0", "react-mosaic-component": "^6.1.1", "react-router": "^7.1.0", + "react-virtuoso": "^4.17.0", "remark-gfm": "^4.0.1", "rxjs": "^7.8.1", "tailwind-merge": "^2.5.5" @@ -8019,6 +8020,16 @@ } } }, + "node_modules/react-virtuoso": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.17.0.tgz", + "integrity": "sha512-od3pi2v13v31uzn5zPXC2u3ouISFCVhjFVFch2VvS2Cx7pWA2F1aJa3XhNTN2F07M3lhfnMnsmGeH+7wZICr7w==", + "license": "MIT", + "peerDependencies": { + "react": ">=16 || >=17 || >= 18 || >= 19", + "react-dom": ">=16 || >=17 || >= 18 || >=19" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 2a7ad44..e4720e6 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "react-medium-image-zoom": "^5.4.0", "react-mosaic-component": "^6.1.1", "react-router": "^7.1.0", + "react-virtuoso": "^4.17.0", "remark-gfm": "^4.0.1", "rxjs": "^7.8.1", "tailwind-merge": "^2.5.5" diff --git a/src/components/ReqViewer.tsx b/src/components/ReqViewer.tsx index 093dee0..dd46b19 100644 --- a/src/components/ReqViewer.tsx +++ b/src/components/ReqViewer.tsx @@ -1,4 +1,5 @@ -import { useState } from "react"; +import { useState, memo } from "react"; +import { Virtuoso } from "react-virtuoso"; import { ChevronDown, ChevronRight, @@ -14,6 +15,12 @@ import { FeedEvent } from "./nostr/Feed"; import { KindBadge } from "./KindBadge"; import type { NostrFilter } from "@/types/nostr"; +// Memoized FeedEvent to prevent unnecessary re-renders during scroll +const MemoizedFeedEvent = memo( + FeedEvent, + (prev, next) => prev.event.id === next.event.id, +); + interface ReqViewerProps { filter: NostrFilter; relays?: string[]; @@ -240,9 +247,14 @@ export default function ReqViewer({ Waiting for events... )} - {events.map((event) => ( - - ))} + {events.length > 0 && ( + event.id} + itemContent={(_index, event) => } + /> + )} );