chore: cleanup subs
This commit is contained in:
parent
a49b40d9b3
commit
3cbec9f272
@ -15,7 +15,7 @@ import LNURLTip from "Element/LNURLTip";
|
||||
import Copy from "Element/Copy";
|
||||
import useProfile from "Feed/ProfileFeed";
|
||||
import useEventPublisher from "Feed/EventPublisher";
|
||||
import { hexToBech32 } from "Util";
|
||||
import { debounce, hexToBech32 } from "Util";
|
||||
import { UserMetadata } from "Nostr";
|
||||
|
||||
type Nip05ServiceProps = {
|
||||
@ -77,7 +77,7 @@ export default function Nip5Service(props: Nip05ServiceProps) {
|
||||
setAvailabilityResponse({ available: false, why: "REGEX" });
|
||||
return;
|
||||
}
|
||||
let t = setTimeout(() => {
|
||||
return debounce(500, () => {
|
||||
svc.CheckAvailable(handle, domain)
|
||||
.then(a => {
|
||||
if ('error' in a) {
|
||||
@ -87,8 +87,7 @@ export default function Nip5Service(props: Nip05ServiceProps) {
|
||||
}
|
||||
})
|
||||
.catch(console.error);
|
||||
}, 500);
|
||||
return () => clearTimeout(t);
|
||||
});
|
||||
}
|
||||
}, [handle, domain]);
|
||||
|
||||
@ -182,7 +181,7 @@ export default function Nip5Service(props: Nip05ServiceProps) {
|
||||
show={showInvoice}
|
||||
onClose={() => setShowInvoice(false)}
|
||||
title={`Buying ${handle}@${domain}`}
|
||||
notice="DO NOT CLOSE THIS POPUP OR YOUR ORDER WILL GET STUCK"/>
|
||||
notice="DO NOT CLOSE THIS POPUP OR YOUR ORDER WILL GET STUCK" />
|
||||
{registerStatus?.paid && <div className="flex f-col">
|
||||
<h4>Order Paid!</h4>
|
||||
<p>Your new NIP-05 handle is: <code>{handle}@{domain}</code></p>
|
||||
|
@ -63,7 +63,7 @@ export default function NoteReaction(props: NoteReactionProps) {
|
||||
const root = extractRoot();
|
||||
const opt = {
|
||||
showHeader: ev?.Kind === EventKind.Repost,
|
||||
showFooter: ev?.Kind === EventKind.Repost,
|
||||
showFooter: false,
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -19,7 +19,7 @@ export interface TimelineProps {
|
||||
* A list of notes by pubkeys
|
||||
*/
|
||||
export default function Timeline({ subject, postsOnly = false, method }: TimelineProps) {
|
||||
const { main, related, latest, loadMore, showLatest } = useTimelineFeed(subject, {
|
||||
const { main, related, latest, parent, loadMore, showLatest } = useTimelineFeed(subject, {
|
||||
method
|
||||
});
|
||||
|
||||
@ -42,7 +42,8 @@ export default function Timeline({ subject, postsOnly = false, method }: Timelin
|
||||
}
|
||||
case EventKind.Reaction:
|
||||
case EventKind.Repost: {
|
||||
return <NoteReaction data={e} key={e.id} />
|
||||
let eRef = e.tags.find(a => a[0] === "e")?.at(1);
|
||||
return <NoteReaction data={e} key={e.id} root={parent.notes.find(a => a.id === eRef)}/>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { useEffect, useMemo, useReducer, useState } from "react";
|
||||
import { System } from "Nostr/System";
|
||||
import { TaggedRawEvent } from "Nostr";
|
||||
import { Subscriptions } from "Nostr/Subscriptions";
|
||||
import { debounce } from "Util";
|
||||
|
||||
export type NoteStore = {
|
||||
notes: Array<TaggedRawEvent>,
|
||||
@ -60,6 +61,11 @@ export interface UseSubscriptionState {
|
||||
append: (notes: TaggedRawEvent[]) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait time before returning changed state
|
||||
*/
|
||||
const DebounceMs = 200;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Subscriptions} sub
|
||||
@ -68,7 +74,16 @@ export interface UseSubscriptionState {
|
||||
*/
|
||||
export default function useSubscription(sub: Subscriptions | null, options?: UseSubscriptionOptions): UseSubscriptionState {
|
||||
const [state, dispatch] = useReducer(notesReducer, initStore);
|
||||
const [debounce, setDebounce] = useState<number>(0);
|
||||
const [debounceOutput, setDebounceOutput] = useState<number>(0);
|
||||
const [subDebounce, setSubDebounced] = useState<Subscriptions>();
|
||||
|
||||
useEffect(() => {
|
||||
if (sub) {
|
||||
return debounce(DebounceMs, () => {
|
||||
setSubDebounced(sub);
|
||||
});
|
||||
}
|
||||
}, [sub]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sub) {
|
||||
@ -99,16 +114,14 @@ export default function useSubscription(sub: Subscriptions | null, options?: Use
|
||||
System.RemoveSubscription(sub.Id);
|
||||
};
|
||||
}
|
||||
}, [sub]);
|
||||
|
||||
}, [subDebounce]);
|
||||
useEffect(() => {
|
||||
let t = setTimeout(() => {
|
||||
setDebounce(s => s += 1);
|
||||
}, 100);
|
||||
return () => clearTimeout(t);
|
||||
return debounce(DebounceMs, () => {
|
||||
setDebounceOutput(s => s += 1);
|
||||
});
|
||||
}, [state]);
|
||||
|
||||
const stateDebounced = useMemo(() => state, [debounce]);
|
||||
const stateDebounced = useMemo(() => state, [debounceOutput]);
|
||||
return {
|
||||
store: stateDebounced,
|
||||
clear: () => {
|
||||
|
@ -6,6 +6,7 @@ import useSubscription from "Feed/Subscription";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "State/Store";
|
||||
import { UserPreferences } from "State/Login";
|
||||
import { debounce } from "Util";
|
||||
|
||||
export default function useThreadFeed(id: u256) {
|
||||
const [trackingEvents, setTrackingEvent] = useState<u256[]>([id]);
|
||||
@ -14,9 +15,8 @@ export default function useThreadFeed(id: u256) {
|
||||
function addId(id: u256[]) {
|
||||
setTrackingEvent((s) => {
|
||||
let orig = new Set(s);
|
||||
let idsMissing = id.filter(a => !orig.has(a));
|
||||
if (idsMissing.length > 0) {
|
||||
let tmp = new Set([...s, ...idsMissing]);
|
||||
if (id.some(a => !orig.has(a))) {
|
||||
let tmp = new Set([...s, ...id]);
|
||||
return Array.from(tmp);
|
||||
} else {
|
||||
return s;
|
||||
@ -41,14 +41,18 @@ export default function useThreadFeed(id: u256) {
|
||||
const main = useSubscription(sub, { leaveOpen: true });
|
||||
|
||||
useEffect(() => {
|
||||
// debounce
|
||||
let t = setTimeout(() => {
|
||||
let eTags = main.store.notes.map(a => a.tags.filter(b => b[0] === "e").map(b => b[1])).flat();
|
||||
let ids = main.store.notes.map(a => a.id);
|
||||
let allEvents = new Set([...eTags, ...ids]);
|
||||
addId(Array.from(allEvents));
|
||||
}, 200);
|
||||
return () => clearTimeout(t);
|
||||
if (main.store) {
|
||||
return debounce(200, () => {
|
||||
let mainNotes = main.store.notes.filter(a => a.kind === EventKind.TextNote);
|
||||
|
||||
let eTags = mainNotes
|
||||
.filter(a => a.kind === EventKind.TextNote)
|
||||
.map(a => a.tags.filter(b => b[0] === "e").map(b => b[1])).flat();
|
||||
let ids = mainNotes.map(a => a.id);
|
||||
let allEvents = new Set([...eTags, ...ids]);
|
||||
addId(Array.from(allEvents));
|
||||
})
|
||||
}
|
||||
}, [main.store]);
|
||||
|
||||
return main.store;
|
||||
|
@ -23,6 +23,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
const [until, setUntil] = useState<number>(now);
|
||||
const [since, setSince] = useState<number>(now - window);
|
||||
const [trackingEvents, setTrackingEvent] = useState<u256[]>([]);
|
||||
const [trackingParentEvents, setTrackingParentEvents] = useState<u256[]>([]);
|
||||
const pref = useSelector<RootState, UserPreferences>(s => s.login.preferences);
|
||||
|
||||
function createSub() {
|
||||
@ -94,18 +95,30 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
const latest = useSubscription(subRealtime, { leaveOpen: true });
|
||||
|
||||
const subNext = useMemo(() => {
|
||||
let sub: Subscriptions | undefined;
|
||||
if (trackingEvents.length > 0 && pref.enableReactions) {
|
||||
let sub = new Subscriptions();
|
||||
sub = new Subscriptions();
|
||||
sub.Id = `timeline-related:${subject.type}`;
|
||||
sub.Kinds = new Set([EventKind.Reaction, EventKind.Deletion, EventKind.Repost]);
|
||||
sub.Kinds = new Set([EventKind.Reaction, EventKind.Deletion]);
|
||||
sub.ETags = new Set(trackingEvents);
|
||||
return sub;
|
||||
}
|
||||
return null;
|
||||
return sub ?? null;
|
||||
}, [trackingEvents]);
|
||||
|
||||
const others = useSubscription(subNext, { leaveOpen: true });
|
||||
|
||||
const subParents = useMemo(() => {
|
||||
if (trackingParentEvents.length > 0) {
|
||||
let parents = new Subscriptions();
|
||||
parents.Id = `timeline-parent:${subject.type}`;
|
||||
parents.Ids = new Set(trackingParentEvents);
|
||||
return parents;
|
||||
}
|
||||
return null;
|
||||
}, [trackingParentEvents]);
|
||||
|
||||
const parent = useSubscription(subParents);
|
||||
|
||||
useEffect(() => {
|
||||
if (main.store.notes.length > 0) {
|
||||
setTrackingEvent(s => {
|
||||
@ -113,6 +126,20 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
let temp = new Set([...s, ...ids]);
|
||||
return Array.from(temp);
|
||||
});
|
||||
let reposts = main.store.notes
|
||||
.filter(a => a.kind === EventKind.Repost && a.content === "")
|
||||
.map(a => a.tags.find(b => b[0] === "e"))
|
||||
.filter(a => a)
|
||||
.map(a => a![1]);
|
||||
if (reposts.length > 0) {
|
||||
setTrackingParentEvents(s => {
|
||||
if (reposts.some(a => !s.includes(a))) {
|
||||
let temp = new Set([...s, ...reposts]);
|
||||
return Array.from(temp);
|
||||
}
|
||||
return s;
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [main.store]);
|
||||
|
||||
@ -120,6 +147,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
main: main.store,
|
||||
related: others.store,
|
||||
latest: latest.store,
|
||||
parent: parent.store,
|
||||
loadMore: () => {
|
||||
console.debug("Timeline load more!")
|
||||
if (options.method === "LIMIT_UNTIL") {
|
||||
|
11
src/Util.ts
11
src/Util.ts
@ -146,3 +146,14 @@ export function extractLnAddress(lnurl: string) {
|
||||
export function unixNow() {
|
||||
return Math.floor(new Date().getTime() / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple debounce
|
||||
* @param timeout Time until falling edge
|
||||
* @param fn Callack to run on falling edge
|
||||
* @returns Cancel timeout function
|
||||
*/
|
||||
export function debounce(timeout: number, fn: () => void) {
|
||||
let t = setTimeout(fn, timeout);
|
||||
return () => clearTimeout(t);
|
||||
}
|
Loading…
Reference in New Issue
Block a user