// @flow import React from 'react'; import type { Node } from 'react'; type InjectedItem = { node: Node, index?: number, replace?: boolean }; /** * Returns the index indicating where in the claim-grid to inject the ad element * @param injectedItem * @param listRef - A reference to the claim-grid * @returns {number} */ export default function useLastVisibleItem(injectedItem: ?InjectedItem, listRef: any) { const [injectedIndex, setInjectedIndex] = React.useState(injectedItem?.index); React.useEffect(() => { // Move to default injection index (last visible item) if (injectedItem && injectedItem.index === undefined) { // AD_INJECTION_DELAY_MS = average total-blocking-time incurred for // loading ads. Delay to let higher priority tasks run first. Ideally, // should use 'requestIdleCallback/requestAnimationFrame'. const AD_INJECTION_DELAY_MS = 1500; const timer = setTimeout(() => { if (listRef.current) { const screenBottom = window.innerHeight; // claim preview tiles const items = listRef.current.children; // algo to return index of item, where ad will be injected before it if (items.length) { let i = 2; // Start from 2, so that the min possible is index-1 for (; i < items.length; ++i) { const rect = items[i].getBoundingClientRect(); if (rect.top > screenBottom || rect.bottom > screenBottom) { break; } } setInjectedIndex(i - 1); return; } } // Fallback to index-1 (2nd item) for failures. No retries. setInjectedIndex(1); }, AD_INJECTION_DELAY_MS); return () => clearTimeout(timer); } }, []); return injectedIndex; }