From 252bcb5de31bb0329f2d771bd07c538e7f60e11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20Kadir=20Ak=C4=B1n?= Date: Fri, 20 Mar 2026 01:12:46 +0300 Subject: [PATCH] refactor(components): refactor Ezoic ad and placeholder components Entire-Checkpoint: afbec17cde9f --- src/components/ads/ezoic-ad.tsx | 17 +++-------------- src/components/ads/ezoic-placeholder.tsx | 14 +++++++------- src/components/layout/ezoic-ads.tsx | 23 +++++++++++++++-------- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/components/ads/ezoic-ad.tsx b/src/components/ads/ezoic-ad.tsx index f52ced82..e9207d3e 100644 --- a/src/components/ads/ezoic-ad.tsx +++ b/src/components/ads/ezoic-ad.tsx @@ -1,6 +1,5 @@ "use client"; -import { useEffect, useState } from "react"; import { EzoicPlaceholder } from "./ezoic-placeholder"; interface EzoicAdProps { @@ -8,20 +7,10 @@ interface EzoicAdProps { } /** - * Client-only wrapper that defers EzoicPlaceholder mounting until after - * hydration. This matches the feed widget pattern where InfinitePromptList - * gates widget rendering behind an isMounted state, ensuring EzoicPlaceholder - * mounts in a separate render pass — after EzoicAds route handler has - * completed its initial destroyPlaceholders/showAds cycle. + * Client-only wrapper for EzoicPlaceholder. + * The placeholder div is always rendered so it's in the DOM when + * Ezoic's showAds() runs — no deferred mounting needed. */ export function EzoicAd({ id }: EzoicAdProps) { - const [mounted, setMounted] = useState(false); - - useEffect(() => { - setMounted(true); - }, []); - - if (!mounted) return null; - return ; } diff --git a/src/components/ads/ezoic-placeholder.tsx b/src/components/ads/ezoic-placeholder.tsx index 3cb1a385..ddabf342 100644 --- a/src/components/ads/ezoic-placeholder.tsx +++ b/src/components/ads/ezoic-placeholder.tsx @@ -10,15 +10,16 @@ interface EzoicPlaceholderProps { export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) { const t = useTranslations("common"); - const [isRendered, setIsRendered] = useState(false); const [hasAdContent, setHasAdContent] = useState(true); const placeholderRef = useRef(null); useEffect(() => { - // Per Ezoic Next.js docs: render the placeholder div first (via state), - // then call showAds(id). The global EzoicRouteHandler's showAds() call - // acts as a safety net to catch all placeholders. - setIsRendered(true); + // The placeholder div is always rendered (no conditional gating), + // so it's in the DOM when this effect runs. Call showAds(id) to + // tell Ezoic to fill it. The global EzoicAds route handler's + // showAds() call acts as an additional safety net. + const el = placeholderRef.current; + runEzoic(() => { window.ezstandalone?.showAds(id); }); @@ -26,7 +27,6 @@ export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) { // Observe the placeholder for ad content injection by Ezoic. // If nothing is injected after a timeout, hide the container // to avoid showing an empty white card. - const el = document.getElementById(`ezoic-pub-ad-placeholder-${id}`); let observer: MutationObserver | undefined; let timeoutId: ReturnType | undefined; @@ -69,7 +69,7 @@ export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) {
- {isRendered &&
} +
); diff --git a/src/components/layout/ezoic-ads.tsx b/src/components/layout/ezoic-ads.tsx index eb77ec03..aa4112f4 100644 --- a/src/components/layout/ezoic-ads.tsx +++ b/src/components/layout/ezoic-ads.tsx @@ -25,10 +25,15 @@ export function EzoicAds() { useEffect(() => { runEzoic(() => { window.ezstandalone?.destroyPlaceholders(); - requestAnimationFrame(() => { + }); + // Delay the global showAds() to give React time to render all + // placeholder divs into the DOM after route change. + const timer = setTimeout(() => { + runEzoic(() => { window.ezstandalone?.showAds(); }); - }); + }, 100); + return () => clearTimeout(timer); }, [pathname]); return ( @@ -47,18 +52,20 @@ export function EzoicAds() { data-cfasync="false" /> + {/* Ezoic init — must run before sa.min.js so the cmd queue exists */} + + {/* Ezoic Header Script */} {/* Ezoic Analytics */}