-
-
Save atomiks/520f4b0c7b537202a23a3059d4eec908 to your computer and use it in GitHub Desktop.
// Will only render the `content` or `render` elements if the tippy is mounted to the DOM. | |
// Replace <Tippy /> with <LazyTippy /> component and it should work the same. | |
const LazyTippy = forwardRef((props, ref) => { | |
const [mounted, setMounted] = useState(false); | |
const lazyPlugin = { | |
fn: () => ({ | |
onMount: () => setMounted(true), | |
onHidden: () => setMounted(false), | |
}), | |
}; | |
const computedProps = {...props}; | |
computedProps.plugins = [lazyPlugin, ...(props.plugins || [])]; | |
if (props.render) { | |
computedProps.render = (...args) => (mounted ? props.render(...args) : ''); | |
} else { | |
computedProps.content = mounted ? props.content : ''; | |
} | |
return <Tippy {...computedProps} ref={ref} />; | |
}); |
// Partially lazy | |
// Will only mount all <Tippy /> content once the singleton itself is mounted. | |
function PartiallyLazySingleton() { | |
const [source, target] = useSingleton(); | |
const [mounted, setMounted] = useState(false); | |
return ( | |
<> | |
<Tippy | |
onShow={() => setMounted(true)} | |
onHidden={() => setMounted(false)} | |
singleton={source} | |
/> | |
<Tippy content={mounted ? <ExpensiveComponent /> : ''} singleton={target}> | |
<button>Hello</button> | |
</Tippy> | |
<Tippy content={mounted ? <ExpensiveComponent /> : ''} singleton={target}> | |
<button>Hello</button> | |
</Tippy> | |
</> | |
); | |
} | |
// Fully lazy | |
// Will only mount the content if that is the currently used singleton content. | |
function LazySingleton() { | |
const [source, target] = useSingleton(); | |
const [mountedRef, setMountedRef] = useState(null); | |
const ref1 = useRef(); | |
const ref2 = useRef(); | |
return ( | |
<> | |
<Tippy | |
onTrigger={(_, event) => setMountedRef(event.currentTarget)} | |
onHidden={() => setMountedRef(null)} | |
singleton={source} | |
/> | |
<Tippy | |
content={mountedRef === ref1.current ? <ExpensiveComponent /> : ''} | |
singleton={target} | |
> | |
<button ref={ref1}>Hello</button> | |
</Tippy> | |
<Tippy | |
content={mountedRef === ref2.current ? <ExpensiveComponent /> : ''} | |
singleton={target} | |
> | |
<button ref={ref2}>Hello</button> | |
</Tippy> | |
</> | |
); | |
} |
Using LazyTippy, I'm getting the following warning in my testing suite:
%chide() was called on a destroyed instance. This is a no-op but indicates a potential memory leak.
It won't happen running a single test, and even if I delete the one it breaks on, it'll just break on another.
Update: we unfortunately have to back out of using Tippy as our test suite doesn't allow warnings and I'm afraid we wouldn't be able to figure this out on our own.
<LazyTippy><LazyTippy><div>Test</div></LazyTippy></LazyTippy>
^--- Nesting multiple lazy tippies gives the error "Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
Any ideas on how to make nesting work?
@wahlstedt you need to forwardRef()
https://github.com/atomiks/tippyjs-react/blob/master/src/forwardRef.js
Updated the example.
Can some add a lazy headless singleton example?
Thanks
Instead of
onMount
to set the mounted state to true, you could tryonShow
in the Lazy example for the moveTransition.