fix: revert to inline mount tracking with useRef

- Replace useMountedState custom hook with inline useRef approach
- Set mountedRef.current = true at start of each effect run
- Ensures proper reset when navigating between articles
- Simpler and more reliable than custom hook approach
This commit is contained in:
Gigi
2025-10-20 18:05:02 +02:00
parent b117b1e6cf
commit dbed4ad253
2 changed files with 28 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, Dispatch, SetStateAction } from 'react' import { useEffect, useRef, Dispatch, SetStateAction } from 'react'
import { RelayPool } from 'applesauce-relay' import { RelayPool } from 'applesauce-relay'
import { fetchArticleByNaddr } from '../services/articleService' import { fetchArticleByNaddr } from '../services/articleService'
import { fetchHighlightsForArticle } from '../services/highlightService' import { fetchHighlightsForArticle } from '../services/highlightService'
@@ -6,7 +6,6 @@ import { ReadableContent } from '../services/readerService'
import { Highlight } from '../types/highlights' import { Highlight } from '../types/highlights'
import { NostrEvent } from 'nostr-tools' import { NostrEvent } from 'nostr-tools'
import { UserSettings } from '../services/settingsService' import { UserSettings } from '../services/settingsService'
import { useMountedState } from './useMountedState'
interface UseArticleLoaderProps { interface UseArticleLoaderProps {
naddr: string | undefined naddr: string | undefined
@@ -37,13 +36,15 @@ export function useArticleLoader({
setCurrentArticle, setCurrentArticle,
settings settings
}: UseArticleLoaderProps) { }: UseArticleLoaderProps) {
const isMounted = useMountedState() const mountedRef = useRef(true)
useEffect(() => { useEffect(() => {
mountedRef.current = true
if (!relayPool || !naddr) return if (!relayPool || !naddr) return
const loadArticle = async () => { const loadArticle = async () => {
if (!isMounted()) return if (!mountedRef.current) return
setReaderLoading(true) setReaderLoading(true)
setReaderContent(undefined) setReaderContent(undefined)
@@ -53,7 +54,7 @@ export function useArticleLoader({
try { try {
const article = await fetchArticleByNaddr(relayPool, naddr, false, settings) const article = await fetchArticleByNaddr(relayPool, naddr, false, settings)
if (!isMounted()) return if (!mountedRef.current) return
setReaderContent({ setReaderContent({
title: article.title, title: article.title,
@@ -74,7 +75,7 @@ export function useArticleLoader({
// Fetch highlights asynchronously without blocking article display // Fetch highlights asynchronously without blocking article display
try { try {
if (!isMounted()) return if (!mountedRef.current) return
setHighlightsLoading(true) setHighlightsLoading(true)
setHighlights([]) setHighlights([])
@@ -84,7 +85,7 @@ export function useArticleLoader({
articleCoordinate, articleCoordinate,
article.event.id, article.event.id,
(highlight) => { (highlight) => {
if (!isMounted()) return if (!mountedRef.current) return
setHighlights((prev: Highlight[]) => { setHighlights((prev: Highlight[]) => {
if (prev.some((h: Highlight) => h.id === highlight.id)) return prev if (prev.some((h: Highlight) => h.id === highlight.id)) return prev
@@ -97,13 +98,13 @@ export function useArticleLoader({
} catch (err) { } catch (err) {
console.error('Failed to fetch highlights:', err) console.error('Failed to fetch highlights:', err)
} finally { } finally {
if (isMounted()) { if (mountedRef.current) {
setHighlightsLoading(false) setHighlightsLoading(false)
} }
} }
} catch (err) { } catch (err) {
console.error('Failed to load article:', err) console.error('Failed to load article:', err)
if (isMounted()) { if (mountedRef.current) {
setReaderContent({ setReaderContent({
title: 'Error Loading Article', title: 'Error Loading Article',
html: `<p>Failed to load article: ${err instanceof Error ? err.message : 'Unknown error'}</p>`, html: `<p>Failed to load article: ${err instanceof Error ? err.message : 'Unknown error'}</p>`,
@@ -115,8 +116,11 @@ export function useArticleLoader({
} }
loadArticle() loadArticle()
return () => {
mountedRef.current = false
}
// Intentionally excluding setter functions from dependencies to prevent race conditions // Intentionally excluding setter functions from dependencies to prevent race conditions
// isMounted is a stable function and doesn't need to be in dependencies
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [naddr, relayPool, settings]) }, [naddr, relayPool, settings])
} }

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo } from 'react' import { useEffect, useRef, useMemo } from 'react'
import { RelayPool } from 'applesauce-relay' import { RelayPool } from 'applesauce-relay'
import { IEventStore } from 'applesauce-core' import { IEventStore } from 'applesauce-core'
import { fetchReadableContent, ReadableContent } from '../services/readerService' import { fetchReadableContent, ReadableContent } from '../services/readerService'
@@ -7,7 +7,6 @@ import { Highlight } from '../types/highlights'
import { useStoreTimeline } from './useStoreTimeline' import { useStoreTimeline } from './useStoreTimeline'
import { eventToHighlight } from '../services/highlightEventProcessor' import { eventToHighlight } from '../services/highlightEventProcessor'
import { KINDS } from '../config/kinds' import { KINDS } from '../config/kinds'
import { useMountedState } from './useMountedState'
// Helper to extract filename from URL // Helper to extract filename from URL
function getFilenameFromUrl(url: string): string { function getFilenameFromUrl(url: string): string {
@@ -49,7 +48,7 @@ export function useExternalUrlLoader({
setCurrentArticleCoordinate, setCurrentArticleCoordinate,
setCurrentArticleEventId setCurrentArticleEventId
}: UseExternalUrlLoaderProps) { }: UseExternalUrlLoaderProps) {
const isMounted = useMountedState() const mountedRef = useRef(true)
// Load cached URL-specific highlights from event store // Load cached URL-specific highlights from event store
const urlFilter = useMemo(() => { const urlFilter = useMemo(() => {
@@ -66,10 +65,12 @@ export function useExternalUrlLoader({
// Load content and start streaming highlights when URL changes // Load content and start streaming highlights when URL changes
useEffect(() => { useEffect(() => {
mountedRef.current = true
if (!relayPool || !url) return if (!relayPool || !url) return
const loadExternalUrl = async () => { const loadExternalUrl = async () => {
if (!isMounted()) return if (!mountedRef.current) return
setReaderLoading(true) setReaderLoading(true)
setReaderContent(undefined) setReaderContent(undefined)
@@ -81,14 +82,14 @@ export function useExternalUrlLoader({
try { try {
const content = await fetchReadableContent(url) const content = await fetchReadableContent(url)
if (!isMounted()) return if (!mountedRef.current) return
setReaderContent(content) setReaderContent(content)
setReaderLoading(false) setReaderLoading(false)
// Fetch highlights for this URL asynchronously // Fetch highlights for this URL asynchronously
try { try {
if (!isMounted()) return if (!mountedRef.current) return
setHighlightsLoading(true) setHighlightsLoading(true)
@@ -112,7 +113,7 @@ export function useExternalUrlLoader({
relayPool, relayPool,
url, url,
(highlight) => { (highlight) => {
if (!isMounted()) return if (!mountedRef.current) return
if (seen.has(highlight.id)) return if (seen.has(highlight.id)) return
seen.add(highlight.id) seen.add(highlight.id)
@@ -130,13 +131,13 @@ export function useExternalUrlLoader({
} catch (err) { } catch (err) {
console.error('Failed to fetch highlights:', err) console.error('Failed to fetch highlights:', err)
} finally { } finally {
if (isMounted()) { if (mountedRef.current) {
setHighlightsLoading(false) setHighlightsLoading(false)
} }
} }
} catch (err) { } catch (err) {
console.error('Failed to load external URL:', err) console.error('Failed to load external URL:', err)
if (isMounted()) { if (mountedRef.current) {
const filename = getFilenameFromUrl(url) const filename = getFilenameFromUrl(url)
setReaderContent({ setReaderContent({
title: filename, title: filename,
@@ -149,8 +150,11 @@ export function useExternalUrlLoader({
} }
loadExternalUrl() loadExternalUrl()
return () => {
mountedRef.current = false
}
// Intentionally excluding setter functions from dependencies to prevent race conditions // Intentionally excluding setter functions from dependencies to prevent race conditions
// isMounted is a stable function and doesn't need to be in dependencies
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [url, relayPool, eventStore, cachedUrlHighlights]) }, [url, relayPool, eventStore, cachedUrlHighlights])