如何将全局滚动事件应用于多个 React 组件?



我正在构建一个 React 应用程序,我想有一个全局 CSS 类,当组件出现在视口中时,该类用于淡入淡出。

jQuery

使用jQuery,我可能会做这样的事情:

const windowHeight = (window.innerHeight || document.documentElement.clientHeight);
const windowWidth = (window.innerWidth || document.documentElement.clientWidth);
isInViewport(el) {
const rect = el.getBoundingClientRect();
const vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
const horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);
return (vertInView && horInView);
};
$(window).scroll(function(e) {
$('.animate').each(function() {
if(isInViewport($(this)[0])) {
$(this).addClass('animate--active');
}
});
});

滚动时,我会使用animate类检查每个元素,如果元素在视口中,请将animate--active类添加到其中,这将淡入。

反应

在 React 中,我将我的isInViewport()函数移动到全局Helpers.js文件中,以便任何组件都可以使用它,但我不得不将滚动事件和动态类添加到每个组件,这会产生大量重复的代码。例如:

import { isInViewport } from './Helpers.js';
function MyComponent(props) {
const [inViewport, setInViewport] = useState(false);
const myComponentRef = useRef();
function handleScroll(e) {
setInViewport(isInViewport(myComponentRef.current));
}
useEffect(() => {
window.addEventListener('scroll', handleScroll);
// unmount
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const classes = (inViewport) ? 'animate animate--active' : 'animate';
return (
<section className={classes} ref={myComponentRef}>
</section>
);
}

据我所知,这将是 React 执行此操作的方式,这确实有效,但同样,这意味着每个组件都需要自己的状态变量、滚动事件和类声明,这加起来会有很多重复。有没有更好的方法

自定义钩子, 自定义钩子, 自定义钩

import { isInViewport } from './Helpers.js';

function useIsInViewPort(ref) {
const [inViewport, setInViewport] = React.useState(false);
function handleScroll(e) {
setInViewport(isInViewport(ref.current));
}
React.useEffect(() => {
window.addEventListener('scroll', handleScroll);
// unmount
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return inViewport;
}

function Acmp(props) {
const ref = React.useRef();
const inViewport = useIsInViewPort(ref); 
const classes = (inViewport) ? 'animate animate--active' : 'animate';
return (
<section className={classes} ref={ref}>
</section>
);
}

function Bcmp(props) {
const ref = React.useRef();
const inViewport = useIsInViewPort(ref); 
return (
<section className={classes} ref={ref}>
</section>
);
}

最新更新