mirror of
https://github.com/dergigi/boris.git
synced 2025-12-17 06:34:24 +01:00
fix: reduce markdown reprocessing to prevent flicker
- Use stable string keys instead of Map objects as dependencies - Only clear rendered HTML when markdown content actually changes - Use refs to access latest Map values without triggering re-renders - Prevents excessive markdown reprocessing on every profile update - Should significantly reduce screen flickering during profile resolution
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useRef } from 'react'
|
||||
import React, { useState, useEffect, useRef, useMemo } from 'react'
|
||||
import { RelayPool } from 'applesauce-relay'
|
||||
import { extractNaddrUris, replaceNostrUrisInMarkdownWithProfileLabels } from '../utils/nostrUriResolver'
|
||||
import { fetchArticleTitles } from '../services/articleTitleResolver'
|
||||
@@ -23,6 +23,35 @@ export const useMarkdownToHTML = (
|
||||
|
||||
// Resolve profile labels progressively as profiles load
|
||||
const { labels: profileLabels, loading: profileLoading } = useProfileLabels(markdown || '', relayPool)
|
||||
|
||||
// Create stable dependencies based on Map contents, not Map objects
|
||||
// This prevents unnecessary reprocessing when Maps are recreated with same content
|
||||
const profileLabelsKey = useMemo(() => {
|
||||
return Array.from(profileLabels.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`).join('|')
|
||||
}, [profileLabels])
|
||||
|
||||
const profileLoadingKey = useMemo(() => {
|
||||
return Array.from(profileLoading.entries())
|
||||
.filter(([, loading]) => loading)
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.map(([k]) => k)
|
||||
.join('|')
|
||||
}, [profileLoading])
|
||||
|
||||
const articleTitlesKey = useMemo(() => {
|
||||
return Array.from(articleTitles.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`).join('|')
|
||||
}, [articleTitles])
|
||||
|
||||
// Keep refs to latest Maps for processing without causing re-renders
|
||||
const profileLabelsRef = useRef(profileLabels)
|
||||
const profileLoadingRef = useRef(profileLoading)
|
||||
const articleTitlesRef = useRef(articleTitles)
|
||||
|
||||
useEffect(() => {
|
||||
profileLabelsRef.current = profileLabels
|
||||
profileLoadingRef.current = profileLoading
|
||||
articleTitlesRef.current = articleTitles
|
||||
}, [profileLabels, profileLoading, articleTitles])
|
||||
|
||||
// Fetch article titles
|
||||
useEffect(() => {
|
||||
@@ -54,15 +83,27 @@ export const useMarkdownToHTML = (
|
||||
return () => { isCancelled = true }
|
||||
}, [markdown, relayPool])
|
||||
|
||||
// Process markdown with progressive profile labels and article titles
|
||||
// Track previous markdown and processed state to detect actual content changes
|
||||
const previousMarkdownRef = useRef<string | undefined>(markdown)
|
||||
const processedMarkdownRef = useRef<string>(processedMarkdown)
|
||||
|
||||
useEffect(() => {
|
||||
console.log(`[profile-loading-debug][markdown-to-html] Processing markdown, profileLabels=${profileLabels.size}, profileLoading=${profileLoading.size}, articleTitles=${articleTitles.size}`)
|
||||
console.log(`[profile-loading-debug][markdown-to-html] Clearing rendered HTML and processed markdown`)
|
||||
// Always clear previous render immediately to avoid showing stale content while processing
|
||||
setRenderedHtml('')
|
||||
setProcessedMarkdown('')
|
||||
processedMarkdownRef.current = processedMarkdown
|
||||
}, [processedMarkdown])
|
||||
|
||||
// Process markdown with progressive profile labels and article titles
|
||||
// Use stable string keys instead of Map objects to prevent excessive reprocessing
|
||||
useEffect(() => {
|
||||
const labelsSize = profileLabelsRef.current.size
|
||||
const loadingSize = profileLoadingRef.current.size
|
||||
const titlesSize = articleTitlesRef.current.size
|
||||
console.log(`[profile-loading-debug][markdown-to-html] Processing markdown, profileLabels=${labelsSize}, profileLoading=${loadingSize}, articleTitles=${titlesSize}`)
|
||||
|
||||
if (!markdown) {
|
||||
setRenderedHtml('')
|
||||
setProcessedMarkdown('')
|
||||
previousMarkdownRef.current = markdown
|
||||
processedMarkdownRef.current = ''
|
||||
return
|
||||
}
|
||||
|
||||
@@ -71,21 +112,27 @@ export const useMarkdownToHTML = (
|
||||
const processMarkdown = () => {
|
||||
try {
|
||||
// Replace nostr URIs with profile labels (progressive) and article titles
|
||||
// Use refs to get latest values without causing dependency changes
|
||||
const processed = replaceNostrUrisInMarkdownWithProfileLabels(
|
||||
markdown,
|
||||
profileLabels,
|
||||
articleTitles,
|
||||
profileLoading
|
||||
profileLabelsRef.current,
|
||||
articleTitlesRef.current,
|
||||
profileLoadingRef.current
|
||||
)
|
||||
|
||||
if (isCancelled) return
|
||||
|
||||
console.log(`[profile-loading-debug][markdown-to-html] Processed markdown, loading states:`, Array.from(profileLoading.entries()).filter(([, l]) => l).map(([e]) => e.slice(0, 16) + '...'))
|
||||
const loadingStates = Array.from(profileLoadingRef.current.entries())
|
||||
.filter(([, l]) => l)
|
||||
.map(([e]) => e.slice(0, 16) + '...')
|
||||
console.log(`[profile-loading-debug][markdown-to-html] Processed markdown, loading states:`, loadingStates)
|
||||
setProcessedMarkdown(processed)
|
||||
processedMarkdownRef.current = processed
|
||||
} catch (error) {
|
||||
console.error(`[markdown-to-html] Error processing markdown:`, error)
|
||||
if (!isCancelled) {
|
||||
setProcessedMarkdown(markdown) // Fallback to original
|
||||
processedMarkdownRef.current = markdown
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,12 +148,24 @@ export const useMarkdownToHTML = (
|
||||
return () => cancelAnimationFrame(rafId)
|
||||
}
|
||||
|
||||
// Only clear previous content if this is the first processing or markdown changed
|
||||
// For profile updates, just reprocess without clearing to avoid flicker
|
||||
const isMarkdownChange = previousMarkdownRef.current !== markdown
|
||||
previousMarkdownRef.current = markdown
|
||||
|
||||
if (isMarkdownChange || !processedMarkdownRef.current) {
|
||||
console.log(`[profile-loading-debug][markdown-to-html] Clearing rendered HTML and processed markdown (markdown changed: ${isMarkdownChange})`)
|
||||
setRenderedHtml('')
|
||||
setProcessedMarkdown('')
|
||||
processedMarkdownRef.current = ''
|
||||
}
|
||||
|
||||
processMarkdown()
|
||||
|
||||
return () => {
|
||||
isCancelled = true
|
||||
}
|
||||
}, [markdown, profileLabels, profileLoading, articleTitles])
|
||||
}, [markdown, profileLabelsKey, profileLoadingKey, articleTitlesKey])
|
||||
|
||||
return { renderedHtml, previewRef, processedMarkdown }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user