Browse Source

make note feeds more performant

imwald
Silberengel 4 months ago
parent
commit
156af22eee
  1. 16
      src/components/NoteCard/index.tsx
  2. 10
      src/components/NoteList/index.tsx
  3. 19
      src/components/Profile/ProfileTimeline.tsx

16
src/components/NoteCard/index.tsx

@ -3,11 +3,11 @@ import { isMentioningMutedUsers } from '@/lib/event'
import { useContentPolicy } from '@/providers/ContentPolicyProvider' import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useMuteList } from '@/providers/MuteListProvider' import { useMuteList } from '@/providers/MuteListProvider'
import { Event, kinds } from 'nostr-tools' import { Event, kinds } from 'nostr-tools'
import { useMemo } from 'react' import { memo, useMemo } from 'react'
import MainNoteCard from './MainNoteCard' import MainNoteCard from './MainNoteCard'
import RepostNoteCard from './RepostNoteCard' import RepostNoteCard from './RepostNoteCard'
export default function NoteCard({ const NoteCard = memo(function NoteCard({
event, event,
className, className,
filterMutedNotes = true filterMutedNotes = true
@ -35,7 +35,17 @@ export default function NoteCard({
) )
} }
return <MainNoteCard event={event} className={className} /> return <MainNoteCard event={event} className={className} />
} }, (prevProps, nextProps) => {
// Custom comparison function for memo
return (
prevProps.event.id === nextProps.event.id &&
prevProps.event.created_at === nextProps.event.created_at &&
prevProps.className === nextProps.className &&
prevProps.filterMutedNotes === nextProps.filterMutedNotes
)
})
export default NoteCard
export function NoteCardLoadingSkeleton() { export function NoteCardLoadingSkeleton() {
return ( return (

10
src/components/NoteList/index.tsx

@ -80,6 +80,14 @@ const NoteList = forwardRef(
const bottomRef = useRef<HTMLDivElement | null>(null) const bottomRef = useRef<HTMLDivElement | null>(null)
const topRef = useRef<HTMLDivElement | null>(null) const topRef = useRef<HTMLDivElement | null>(null)
// Memoize subRequests serialization to avoid expensive JSON.stringify on every render
const subRequestsKey = useMemo(() => {
return JSON.stringify(subRequests.map(req => ({
urls: [...req.urls].sort(), // Create a copy before sorting to avoid mutation
filter: req.filter
})))
}, [subRequests])
const shouldHideEvent = useCallback( const shouldHideEvent = useCallback(
(evt: Event) => { (evt: Event) => {
const pinnedEventHexIdSet = new Set() const pinnedEventHexIdSet = new Set()
@ -252,7 +260,7 @@ const NoteList = forwardRef(
return () => { return () => {
promise.then((closer) => closer()) promise.then((closer) => closer())
} }
}, [JSON.stringify(subRequests), refreshCount, showKinds]) }, [subRequestsKey, refreshCount, showKinds])
useEffect(() => { useEffect(() => {
const options = { const options = {

19
src/components/Profile/ProfileTimeline.tsx

@ -92,12 +92,19 @@ const ProfileTimeline = forwardRef<
if (!searchQuery.trim()) { if (!searchQuery.trim()) {
return eventsFilteredByKind return eventsFilteredByKind
} }
const query = searchQuery.toLowerCase() // Pre-compute lowercase query once
return eventsFilteredByKind.filter( const query = searchQuery.toLowerCase().trim()
(event) => // Pre-compute lowercase content and tags for each event to avoid repeated conversions
event.content.toLowerCase().includes(query) || return eventsFilteredByKind.filter((event) => {
event.tags.some((tag) => tag.length > 1 && tag[1]?.toLowerCase().includes(query)) const contentLower = event.content.toLowerCase()
) if (contentLower.includes(query)) return true
// Only check tags if content doesn't match
return event.tags.some((tag) => {
if (tag.length <= 1) return false
const tagValue = tag[1]
return tagValue && tagValue.toLowerCase().includes(query)
})
})
}, [eventsFilteredByKind, searchQuery]) }, [eventsFilteredByKind, searchQuery])
// Reset showCount when filters change // Reset showCount when filters change

Loading…
Cancel
Save