英文:
React : render a component only when they are visible ( react-intersection-observer )
问题
使用 react-intersection-observer(而不创建额外的 div)来实现的最佳方式是仅在这些组件可见时进行渲染。渲染后,我们不希望它们再次变为不可见。
英文:
We have some components that we want to render only once they are visible. Once rendered we do not want them to be invisible again.
What is the best way to do this with react-intersection-observer (without creating additional divs) ?
答案1
得分: 1
使用 triggerOnce
选项,以避免在第一次更改后跟踪可见状态:
const { ref, inView } = useInView({
threshold: 0,
triggerOnce: true
});
英文:
Use the triggerOnce
option to avoid tracking the visibility state after the 1st change:
const { ref, inView } = useInView({
threshold: 0,
triggerOnce: true
});
答案2
得分: 0
以下是您要翻译的内容:
It's not working in all scenarios so we implemented our own hook using IntersectionObserver:
// should not be the case on modern browsers
const hasIntersectionObserver: boolean = 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window
&& 'isIntersecting' in window.IntersectionObserverEntry.prototype;
/**
/* returns [ref, isVisible]
/* ref is to be used in the element we want to check visibility
/* i.e: <div ref={ref} />
**/
export function useOnWhenVisible(alwaysVisible: boolean): [(el: Element) => void, boolean] {
const [ref, setRef] = useState<Element>();
const [isVisible, setIsVisible] = useState<boolean>(alwaysVisible || !hasIntersectionObserver);
useEffect(() => {
// it's just done once
if (ref == null || isVisible) {
return undefined;
}
const observer = new IntersectionObserver([entry] => {
if (entry.isIntersecting) {
setIsVisible(true)
}
});
observer.observe(ref);
return () => {
observer.disconnect();
}
}, [setIsVisible, ref, isVisible]);
return [setRef, isVisible];
}
英文:
It's not working an all scenarios so we implemented our own hook using IntersectionObserver :
// should not be the case on modern browsers
const hasIntersectionObserver: boolean = 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window
&& 'isIntersecting' in window.IntersectionObserverEntry.prototype;
/**
/* returns [ref,isVisible]
/* ref is to be used in the element we want to check visibility
/* i.e : <div ref={ref} />
**/
export function useOnWhenVisible(alwaysVisible: boolean): [(el: Element) => void, boolean] {
const [ref, setRef] = useState<Element>();
const [isVisible, setIsVisible] = useState<boolean>(alwaysVisible || !hasIntersectionObserver);
useEffect(() => {
// it's just done once
if (ref == null || isVisible) {
return undefined;
}
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true)
}
});
observer.observe(ref);
return () => {
observer.disconnect();
}
}, [setIsVisible, ref, isVisible]);
return [setRef, isVisible];
}
答案3
得分: 0
几天前,我遇到了类似的问题,但尚未解决。在我使用的库(preact-intersection-observer)中,有几个选项:rootMargin、threshold、defaultInView、triggerOnce。但主要问题出现在重新渲染元素时。当网站首次加载时,一切都正常运作,但在单击购物车图标或登录后,页面重新渲染,似乎观察者不再跟踪后续操作,尽管在单击按钮时它写入ref.current等于正确的div。但与此同时,我看到一个高度为22px的小条带,也许是异步加载的preact组件没有加载。如果将triggerOnce更改为false,一切正常运作,但我们还会看到已卸载组件的永久触发。也许问题出在以下代码的部分:
// 如果窗口被定义,且观察者未被定义
if (!!window && !observer.current) {
observer.current = new IntersectionObserver(
(entries) => {
entry.current = entries[0];
setInView(entries[0].isIntersecting);
},
{
...options,
root: ref.current,
}
);
}
英文:
A few days ago, I encountered a similar problem, but have not yet solved it.
In the library I used (preact-intersection-observer).
there are several options:
rootMargin,
threshold,
defaultInView,
triggerOnce
but the main problem arose when re-rendering the elements.
When the site loaded for the first time, everything worked fine,
but after clicking on the cart icon, or login,
the page was rerendered,
and it seems that the observer did not track further actions, although it writes when the button is clicked that the ref.current is equal to the correct div.
But at the same time, I see a small strip 22px high,
maybe it's the async lazy preact that doesn't load the component.
If we change triggerOnce on false, all works fine, but we also see permanent trigering on off mounted components.
Maybe problem in that part of code:
// If window is defined, and the observer isn't defined
if (!!window && !observer.current) {
observer.current = new IntersectionObserver(
(entries) => {
entry.current = entries[0];
setInView(entries[0].isIntersecting);
},
{
...options,
root: ref.current,
}
);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论