improve timeline render performance

This commit is contained in:
hzrd149
2023-06-30 07:22:18 -05:00
parent c036a9a541
commit 1fbc6bfb96
5 changed files with 32 additions and 44 deletions

View File

@@ -0,0 +1,23 @@
import React from "react";
import useSubject from "../hooks/use-subject";
import { TimelineLoader } from "../classes/timeline-loader";
import RepostNote from "./repost-note";
import { Note } from "./note";
const GenericNoteTimeline = React.memo(({ timeline }: { timeline: TimelineLoader }) => {
const notes = useSubject(timeline.timeline);
return (
<>
{notes.map((note) =>
note.kind === 6 ? (
<RepostNote key={note.id} event={note} maxHeight={1200} />
) : (
<Note key={note.id} event={note} maxHeight={1200} />
)
)}
</>
);
});
export default GenericNoteTimeline;

View File

@@ -19,7 +19,6 @@ import { useAppTitle } from "../../hooks/use-app-title";
import { useReadRelayUrls } from "../../hooks/use-client-relays"; import { useReadRelayUrls } from "../../hooks/use-client-relays";
import { useTimelineLoader } from "../../hooks/use-timeline-loader"; import { useTimelineLoader } from "../../hooks/use-timeline-loader";
import { isReply } from "../../helpers/nostr-event"; import { isReply } from "../../helpers/nostr-event";
import { Note } from "../../components/note";
import { CheckIcon, EditIcon, RelayIcon } from "../../components/icons"; import { CheckIcon, EditIcon, RelayIcon } from "../../components/icons";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import RelaySelectionModal from "./relay-selection-modal"; import RelaySelectionModal from "./relay-selection-modal";
@@ -27,7 +26,7 @@ import { NostrEvent } from "../../types/nostr-event";
import TimelineActionAndStatus from "../../components/timeline-action-and-status"; import TimelineActionAndStatus from "../../components/timeline-action-and-status";
import IntersectionObserverProvider from "../../providers/intersection-observer"; import IntersectionObserverProvider from "../../providers/intersection-observer";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback"; import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import useSubject from "../../hooks/use-subject"; import GenericNoteTimeline from "../../components/generric-note-timeline";
function EditableControls() { function EditableControls() {
const { isEditing, getSubmitButtonProps, getCancelButtonProps, getEditButtonProps } = useEditableControls(); const { isEditing, getSubmitButtonProps, getCancelButtonProps, getEditButtonProps } = useEditableControls();
@@ -69,8 +68,6 @@ export default function HashTagView() {
{ eventFilter } { eventFilter }
); );
const events = useSubject(timeline.timeline);
const scrollBox = useRef<HTMLDivElement | null>(null); const scrollBox = useRef<HTMLDivElement | null>(null);
const callback = useTimelineCurserIntersectionCallback(timeline); const callback = useTimelineCurserIntersectionCallback(timeline);
@@ -118,10 +115,8 @@ export default function HashTagView() {
</FormLabel> </FormLabel>
</FormControl> </FormControl>
</Flex> </Flex>
{events.map((event) => (
<Note key={event.id} event={event} maxHeight={600} />
))}
<GenericNoteTimeline timeline={timeline} />
<TimelineActionAndStatus timeline={timeline} /> <TimelineActionAndStatus timeline={timeline} />
</Flex> </Flex>
</IntersectionObserverProvider> </IntersectionObserverProvider>

View File

@@ -1,6 +1,5 @@
import { Button, Flex, FormControl, FormLabel, Switch } from "@chakra-ui/react"; import { Button, Flex, FormControl, FormLabel, Switch } from "@chakra-ui/react";
import { useSearchParams } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { Note } from "../../components/note";
import { isReply, truncatedId } from "../../helpers/nostr-event"; import { isReply, truncatedId } from "../../helpers/nostr-event";
import { useTimelineLoader } from "../../hooks/use-timeline-loader"; import { useTimelineLoader } from "../../hooks/use-timeline-loader";
import { useUserContacts } from "../../hooks/use-user-contacts"; import { useUserContacts } from "../../hooks/use-user-contacts";
@@ -9,13 +8,12 @@ import { useCallback, useContext, useRef } from "react";
import { PostModalContext } from "../../providers/post-modal-provider"; import { PostModalContext } from "../../providers/post-modal-provider";
import { useReadRelayUrls } from "../../hooks/use-client-relays"; import { useReadRelayUrls } from "../../hooks/use-client-relays";
import { useCurrentAccount } from "../../hooks/use-current-account"; import { useCurrentAccount } from "../../hooks/use-current-account";
import RepostNote from "../../components/repost-note";
import RequireCurrentAccount from "../../providers/require-current-account"; import RequireCurrentAccount from "../../providers/require-current-account";
import { NostrEvent } from "../../types/nostr-event"; import { NostrEvent } from "../../types/nostr-event";
import TimelineActionAndStatus from "../../components/timeline-action-and-status"; import TimelineActionAndStatus from "../../components/timeline-action-and-status";
import IntersectionObserverProvider from "../../providers/intersection-observer"; import IntersectionObserverProvider from "../../providers/intersection-observer";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback"; import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import useSubject from "../../hooks/use-subject"; import GenericNoteTimeline from "../../components/generric-note-timeline";
function FollowingTabBody() { function FollowingTabBody() {
const account = useCurrentAccount()!; const account = useCurrentAccount()!;
@@ -44,8 +42,6 @@ function FollowingTabBody() {
{ enabled: following.length > 0, eventFilter } { enabled: following.length > 0, eventFilter }
); );
const events = useSubject(timeline.timeline);
const scrollBox = useRef<HTMLDivElement | null>(null); const scrollBox = useRef<HTMLDivElement | null>(null);
const callback = useTimelineCurserIntersectionCallback(timeline); const callback = useTimelineCurserIntersectionCallback(timeline);
@@ -67,13 +63,8 @@ function FollowingTabBody() {
</FormLabel> </FormLabel>
<Switch id="show-replies" isChecked={showReplies} onChange={onToggle} /> <Switch id="show-replies" isChecked={showReplies} onChange={onToggle} />
</FormControl> </FormControl>
{events.map((event) =>
event.kind === 6 ? ( <GenericNoteTimeline timeline={timeline} />
<RepostNote key={event.id} event={event} maxHeight={600} />
) : (
<Note key={event.id} event={event} maxHeight={600} />
)
)}
<TimelineActionAndStatus timeline={timeline} /> <TimelineActionAndStatus timeline={timeline} />
</Flex> </Flex>

View File

@@ -1,7 +1,6 @@
import { useCallback, useRef } from "react"; import { useCallback, useRef } from "react";
import { Flex, FormControl, FormLabel, Select, Switch, useDisclosure } from "@chakra-ui/react"; import { Flex, FormControl, FormLabel, Select, Switch, useDisclosure } from "@chakra-ui/react";
import { useSearchParams } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { Note } from "../../components/note";
import { unique } from "../../helpers/array"; import { unique } from "../../helpers/array";
import { isReply } from "../../helpers/nostr-event"; import { isReply } from "../../helpers/nostr-event";
import { useAppTitle } from "../../hooks/use-app-title"; import { useAppTitle } from "../../hooks/use-app-title";
@@ -9,9 +8,9 @@ import { useReadRelayUrls } from "../../hooks/use-client-relays";
import { useTimelineLoader } from "../../hooks/use-timeline-loader"; import { useTimelineLoader } from "../../hooks/use-timeline-loader";
import { NostrEvent } from "../../types/nostr-event"; import { NostrEvent } from "../../types/nostr-event";
import TimelineActionAndStatus from "../../components/timeline-action-and-status"; import TimelineActionAndStatus from "../../components/timeline-action-and-status";
import useSubject from "../../hooks/use-subject";
import IntersectionObserverProvider from "../../providers/intersection-observer"; import IntersectionObserverProvider from "../../providers/intersection-observer";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback"; import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import GenericNoteTimeline from "../../components/generric-note-timeline";
export default function GlobalTab() { export default function GlobalTab() {
useAppTitle("global"); useAppTitle("global");
@@ -42,8 +41,6 @@ export default function GlobalTab() {
{ eventFilter } { eventFilter }
); );
const events = useSubject(timeline.timeline);
const scrollBox = useRef<HTMLDivElement | null>(null); const scrollBox = useRef<HTMLDivElement | null>(null);
const callback = useTimelineCurserIntersectionCallback(timeline); const callback = useTimelineCurserIntersectionCallback(timeline);
@@ -72,10 +69,8 @@ export default function GlobalTab() {
</FormLabel> </FormLabel>
</FormControl> </FormControl>
</Flex> </Flex>
{events.map((event) => (
<Note key={event.id} event={event} maxHeight={600} />
))}
<GenericNoteTimeline timeline={timeline} />
<TimelineActionAndStatus timeline={timeline} /> <TimelineActionAndStatus timeline={timeline} />
</Flex> </Flex>
</IntersectionObserverProvider> </IntersectionObserverProvider>

View File

@@ -14,22 +14,7 @@ import TimelineActionAndStatus from "../../components/timeline-action-and-status
import IntersectionObserverProvider from "../../providers/intersection-observer"; import IntersectionObserverProvider from "../../providers/intersection-observer";
import { TimelineLoader } from "../../classes/timeline-loader"; import { TimelineLoader } from "../../classes/timeline-loader";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback"; import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import GenericNoteTimeline from "../../components/generric-note-timeline";
const NoteTimeline = React.memo(({ timeline }: { timeline: TimelineLoader }) => {
const notes = useSubject(timeline.timeline);
return (
<>
{notes.map((note) =>
note.kind === 6 ? (
<RepostNote key={note.id} event={note} maxHeight={1200} />
) : (
<Note key={note.id} event={note} maxHeight={1200} />
)
)}
</>
);
});
const UserNotesTab = () => { const UserNotesTab = () => {
const { pubkey } = useOutletContext() as { pubkey: string }; const { pubkey } = useOutletContext() as { pubkey: string };
@@ -76,8 +61,7 @@ const UserNotesTab = () => {
<RelayIconStack ml="auto" relays={readRelays} direction="row-reverse" mr="4" maxRelays={4} /> <RelayIconStack ml="auto" relays={readRelays} direction="row-reverse" mr="4" maxRelays={4} />
</FormControl> </FormControl>
<NoteTimeline timeline={timeline} /> <GenericNoteTimeline timeline={timeline} />
<TimelineActionAndStatus timeline={timeline} /> <TimelineActionAndStatus timeline={timeline} />
</Flex> </Flex>
</IntersectionObserverProvider> </IntersectionObserverProvider>