lbry-desktop/ui/effects/use-last-visible-item.js
infinite-persistence 0143b63c74 Ads: replace DOM manipulations with React components
- Instead of 2 ways to display ads (DOM injection + React method) and having both of them clash, just do it the predictable React way.
    - Augment the existing React version to support tile layout + ability to place in last visible slot.
    - Consolidate styling code to scss ... DOM manipulations were making it even harder to maintain.
    - Removed the need to check for ad-blockers for now. It was being executed every time an ad is displayed, and now that we are displaying ads in more places, the gains doesn't justify the performance loss. Also, it wasn't being done for Recommended ads anyway, so the inconsistency probably means it's not needed in the first place.

Other known issues fixed:
- double ad injection when changing language via nag.
- additional "total-blocking-time" due to ads at startup removed.
- fixed ads not appearing in mobile homepage until navigated away and back to homepage.
- enable ads in channel page.
- support for both List and Tile layout.
2022-03-08 10:53:52 -05:00

46 lines
1.5 KiB
JavaScript

// @flow
import React from 'react';
import type { Node } from 'react';
type InjectedItem = { node: Node, index?: number, replace?: boolean };
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;
const items = listRef.current.children;
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;
}