使用 React Hooks 更新带滚动

IT技术 javascript reactjs react-hooks
2021-04-27 11:59:26

我试图根据个人是否在组件上向下滚动来控制 React 组件的可见性。可见性Fade作为“in”属性传递到元素中。

我已经使用 UseEffect Hook 设置了一个侦听器,它添加了 onMount 侦听器。实际的 onScroll 函数应该更新 scrollTop 状态(它是到页面顶部的高度的当前值),然后是滚动状态(将事件的滚动到页面顶部与之前的状态进行比较,以及如果第一个大于第二个,则返回 true)。

但是,由于某种原因 setScrollTop 钩子不起作用,滚动状态继续保持在 0。

我究竟做错了什么?这是完整的组件:

export const Header = (props) => {

  const classes = useStyles();

  const [scrolling, setScrolling] = useState(false);
  const [scrollTop, setScrollTop] = useState(0);

  const onScroll = (e) => {
    setScrollTop(e.target.documentElement.scrollTop);
    setScrolling(e.target.documentElement.scrollTop > scrollTop);
  }

  useEffect(() => {
    window.addEventListener('scroll', onScroll);
  },[]);

  useEffect(() => {
    console.log(scrollTop);
  }, [scrollTop])

  return (
   <Fade in={!scrolling}>
      <AppBar className={classes.header} position="fixed">

  ....
2个回答

您缺少钩子中的依赖项。试试这个:

  useEffect(() => {
    const onScroll = e => {
      setScrollTop(e.target.documentElement.scrollTop);
      setScrolling(e.target.documentElement.scrollTop > scrollTop);
    };
    window.addEventListener("scroll", onScroll);

    return () => window.removeEventListener("scroll", onScroll);
  }, [scrollTop]);

通过在onScroll内部移动useEffect,您不需要在钩子的依赖项上跟踪它,但是由于它scrollTop从组件的范围内使用,您需要添加它。

另外,如果由于某种原因,你不希望移动onScroll内部的定义useEffect,你需要包装onScrolluseCallback,并跟踪它useEffect的依赖性阵列。

一般来说,我建议添加react-hooks/exhaustive-deps到您的 ESlint 规则中

此外,删除清理函数中的事件侦听器也是一个好主意。

或者您可以使用 window.pageYOffset。这样对我来说更容易理解:

const [scrolling, setScrolling] = useState(false);
  const [scrollTop, setScrollTop] = useState(0);

  useEffect(() => {
    function onScroll() {
      let currentPosition = window.pageYOffset; // or use document.documentElement.scrollTop;
      if (currentPosition > scrollTop) {
        // downscroll code
        setScrolling(false);
      } else {
        // upscroll code
        setScrolling(true);
      }
      setScrollTop(currentPosition <= 0 ? 0 : currentPosition);
    }

    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, [scrollTop]);