From 6262408fbeebb7ffc186df561842f0ebf976affd Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Fri, 30 Oct 2026 22:39:21 -0700 Subject: [PATCH] fix(favicons): let a mounted icon retry once its failure ages out A failed load set per-instance state that pinned the icon to its fallback until it unmounted, so the five-minute miss window never reached an icon already on screen. The module-level miss cache is now the only failure record; a reducer only re-renders on error, so the next render after the entry expires asks again (a confirmed miss is still answered from the HTTP cache). --- apps/sim/components/favicon.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/sim/components/favicon.tsx b/apps/sim/components/favicon.tsx index 89cf0ab72b1..20c6257b2f6 100644 --- a/apps/sim/components/favicon.tsx +++ b/apps/sim/components/favicon.tsx @@ -1,14 +1,15 @@ 'use client' -import { type ReactNode, useState } from 'react' +import { type ReactNode, useReducer } from 'react' import { cn } from '@sim/emcn' import { LRUCache } from 'lru-cache' import { faviconSrc } from '@/lib/favicon/url' /** - * Hosts whose icon just failed, so an icon that mounts again renders its fallback at once - * instead of an empty slot first. An `` can't tell no icon from a provider outage, so this - * lasts only as long as the route retries an outage; a confirmed miss stays in the HTTP cache. + * Hosts whose icon failed recently: the only failure record, so mounted and remounted icons + * render the fallback at once instead of an empty slot. An `` can't tell no icon from a + * provider outage, so an entry lasts only as long as the route retries an outage; the next render + * after that asks again, and a confirmed miss stays in the HTTP cache. */ const knownMisses = new LRUCache({ max: 500, ttl: 5 * 60 * 1000 }) @@ -27,8 +28,8 @@ interface FaviconProps { * of a provider's placeholder. */ export function Favicon({ host, fallback, className }: FaviconProps) { - const [failedHost, setFailedHost] = useState(null) - if (!host || failedHost === host || knownMisses.has(host)) return fallback + const [, rerender] = useReducer((failures: number) => failures + 1, 0) + if (!host || knownMisses.has(host)) return fallback return ( { knownMisses.set(host, true) - setFailedHost(host) + rerender() }} /> )