mirror of
https://github.com/hoornet/vega.git
synced 2026-07-20 23:38:10 -07:00
Optimize rendering: memo, granular selectors, code splitting
- React.memo on NoteCard and ArticleCard to skip re-renders - Granular Zustand selectors in Feed.tsx and NoteCard.tsx - Lazy-load 19 views with React.lazy + Suspense boundary
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { memo } from "react";
|
||||
import { NDKEvent, nip19 } from "@nostr-dev-kit/ndk";
|
||||
import { useProfile } from "../../hooks/useProfile";
|
||||
import { useUIStore } from "../../stores/ui";
|
||||
@@ -21,7 +22,7 @@ function buildNaddr(event: NDKEvent): string {
|
||||
});
|
||||
}
|
||||
|
||||
export function ArticleCard({ event }: { event: NDKEvent }) {
|
||||
export const ArticleCard = memo(function ArticleCard({ event }: { event: NDKEvent }) {
|
||||
const { openArticle, openProfile } = useUIStore();
|
||||
const profile = useProfile(event.pubkey);
|
||||
|
||||
@@ -117,4 +118,4 @@ export function ArticleCard({ event }: { event: NDKEvent }) {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,10 +24,25 @@ function timeAgo(ts: number): string {
|
||||
}
|
||||
|
||||
export function Feed() {
|
||||
const { notes, loading, error, connect, loadCachedFeed, loadFeed, trendingNotes, trendingLoading, loadTrendingFeed, focusedNoteIndex, lastUpdated } = useFeedStore();
|
||||
const { loggedIn, follows } = useUserStore();
|
||||
const { mutedPubkeys, contentMatchesMutedKeyword } = useMuteStore();
|
||||
const { feedTab: tab, setFeedTab: setTab, feedLanguageFilter, setFeedLanguageFilter } = useUIStore();
|
||||
const notes = useFeedStore((s) => s.notes);
|
||||
const loading = useFeedStore((s) => s.loading);
|
||||
const error = useFeedStore((s) => s.error);
|
||||
const connect = useFeedStore((s) => s.connect);
|
||||
const loadCachedFeed = useFeedStore((s) => s.loadCachedFeed);
|
||||
const loadFeed = useFeedStore((s) => s.loadFeed);
|
||||
const trendingNotes = useFeedStore((s) => s.trendingNotes);
|
||||
const trendingLoading = useFeedStore((s) => s.trendingLoading);
|
||||
const loadTrendingFeed = useFeedStore((s) => s.loadTrendingFeed);
|
||||
const focusedNoteIndex = useFeedStore((s) => s.focusedNoteIndex);
|
||||
const lastUpdated = useFeedStore((s) => s.lastUpdated);
|
||||
const loggedIn = useUserStore((s) => s.loggedIn);
|
||||
const follows = useUserStore((s) => s.follows);
|
||||
const mutedPubkeys = useMuteStore((s) => s.mutedPubkeys);
|
||||
const contentMatchesMutedKeyword = useMuteStore((s) => s.contentMatchesMutedKeyword);
|
||||
const tab = useUIStore((s) => s.feedTab);
|
||||
const setTab = useUIStore((s) => s.setFeedTab);
|
||||
const feedLanguageFilter = useUIStore((s) => s.feedLanguageFilter);
|
||||
const setFeedLanguageFilter = useUIStore((s) => s.setFeedLanguageFilter);
|
||||
const [followNotes, setFollowNotes] = useState<NDKEvent[]>([]);
|
||||
const [followLoading, setFollowLoading] = useState(false);
|
||||
const [, setTick] = useState(0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useState, useRef, useEffect, memo } from "react";
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
import { useProfile } from "../../hooks/useProfile";
|
||||
import { useNip05Verified } from "../../hooks/useNip05Verified";
|
||||
@@ -25,7 +25,7 @@ function ParentAuthorName({ pubkey }: { pubkey: string }) {
|
||||
return <span className="text-accent">@{name}</span>;
|
||||
}
|
||||
|
||||
export function NoteCard({ event, focused, onReplyInThread }: NoteCardProps) {
|
||||
export const NoteCard = memo(function NoteCard({ event, focused, onReplyInThread }: NoteCardProps) {
|
||||
const profile = useProfile(event.pubkey);
|
||||
const rawName = profile?.displayName || profile?.name;
|
||||
const name = (typeof rawName === "string" ? rawName : null) || shortenPubkey(event.pubkey);
|
||||
@@ -34,10 +34,18 @@ export function NoteCard({ event, focused, onReplyInThread }: NoteCardProps) {
|
||||
const verified = useNip05Verified(event.pubkey, nip05);
|
||||
const time = event.created_at ? timeAgo(event.created_at) : "";
|
||||
|
||||
const { loggedIn, pubkey: ownPubkey, follows, follow, unfollow } = useUserStore();
|
||||
const { mutedPubkeys, mute, unmute } = useMuteStore();
|
||||
const loggedIn = useUserStore((s) => s.loggedIn);
|
||||
const ownPubkey = useUserStore((s) => s.pubkey);
|
||||
const follows = useUserStore((s) => s.follows);
|
||||
const follow = useUserStore((s) => s.follow);
|
||||
const unfollow = useUserStore((s) => s.unfollow);
|
||||
const mutedPubkeys = useMuteStore((s) => s.mutedPubkeys);
|
||||
const mute = useMuteStore((s) => s.mute);
|
||||
const unmute = useMuteStore((s) => s.unmute);
|
||||
const isMuted = mutedPubkeys.includes(event.pubkey);
|
||||
const { openProfile, openThread, currentView } = useUIStore();
|
||||
const openProfile = useUIStore((s) => s.openProfile);
|
||||
const openThread = useUIStore((s) => s.openThread);
|
||||
const currentView = useUIStore((s) => s.currentView);
|
||||
|
||||
const parentEventId = getParentEventId(event);
|
||||
// The immediate parent author is typically the last p tag (NIP-10 ordering mirrors e tags).
|
||||
@@ -194,4 +202,4 @@ export function NoteCard({ event, focused, onReplyInThread }: NoteCardProps) {
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user