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) => }
+ />
+ )}
);