粘性 header 滚动隐藏和显示

Sticky header with hide and show on scroll

我有一个由两部分组成的导航栏(navbarTop 和 navbarBottom);当 scrollY 大于 110 时将显示 navbarTop 并且当用户向上滚动时将显示 navbarbottom ,但我的问题是每个组件将在每次滚动后 re-called ,甚至向下滚动,或者当 navbottom 已经存在并且用户向上滚动,它仍然继续调用该组件。 这是代码:

const Navbar: FC = () => {

const [stickyHeader, setStickyHeader] = useState(false);
const [stickyMenu, setStickyMenu] = useState(false);

console.log('navbar')

const [y, setY] = useState(null);
const handleNavigation = useCallback(
    (e) => {
        const window = e.currentTarget;
        if (!stickyMenu) {
            if (y > window.scrollY) {
                setStickyMenu(true)
                // console.log("scrolling up");
            }
        }
        if (!stickyHeader) {
            if (window.scrollY >= 110) {
                setStickyHeader(true);
            }
        }
        if (stickyHeader) {
            if (window.scrollY <= 110) {
                setStickyHeader(false);
            }
        }
        if (stickyMenu) {
            if (y < window.scrollY) {
                setStickyMenu(false)
                // console.log("scrolling down");
            }
        }

        setY(window.scrollY);
    },
    [y, stickyMenu,stickyHeader]
);


useEffect(() => {
    window.addEventListener("scroll", handleNavigation);

    return () => {
        window.removeEventListener("scroll", handleNavigation);
    };
}, [handleNavigation, stickyMenu]);



return (
    <>
        <div className={s.root}>

            {stickyHeader === false ? (
                <div className='hidden xl:block md:w-auto'>
                    <NavbarTop sticky={false}/>
                    <NavbarBottom
                        sticky={false}/>
                </div>
            ) : (
                <div className='absolute hidden xl:block md:w-auto'>
                    <NavbarTop sticky={true}/>
                    {stickyMenu &&
                        <NavbarBottom sticky={true}/>
                    }
                </div>
            )}

            <SmallNav/>
        </div>
    </>

)

} 导出默认导航栏

其实我不是很明白你的问题。你说每个组件在每次滚动后都是re-called。当然是re-called对吧?

无论何时滚动,都会更改 stickyHeaderstickyMenu。 React 监听状态变化和 re-renders 组件。这就是 React 的工作原理。

我看到您正在使用 tailwindcss。

可以先用一个useMemo监听状态然后根据不同的状态return适当的class。这样您就可以避免一遍又一遍地创建 DOM 个节点。我不知道这是否对你有帮助。希望对您有所帮助。

const Navbar: FC = () => {
    const [stickyHeader, setStickyHeader] = useState(false);
    const [stickyMenu, setStickyMenu] = useState(false);
    // console.log('navbar');

    const [y, setY] = useState(null);
    const handleNavigation = useCallback(
        (e) => {
            const window = e.currentTarget;
            if (!stickyMenu) {
                if (y > window.scrollY) {
                    setStickyMenu(true);
                    // console.log("scrolling up");
                }
            }
            if (!stickyHeader) {
                if (window.scrollY >= 110) {
                    setStickyHeader(true);
                }
            }
            if (stickyHeader) {
                if (window.scrollY <= 110) {
                    setStickyHeader(false);
                }
            }
            if (stickyMenu) {
                if (y < window.scrollY) {
                    setStickyMenu(false);
                    // console.log("scrolling down");
                }
            }

            setY(window.scrollY);
        },
        [y, stickyMenu, stickyHeader],
    );

    useEffect(() => {
        window.addEventListener('scroll', handleNavigation);

        return () => {
            window.removeEventListener('scroll', handleNavigation);
        };
    }, [handleNavigation, stickyMenu]);

    const stickyClassName = useMemo(() => {
        if (stickyHeader) {
            return 'sticky top-0 xl:block md:w-auto';
        }
        return 'xl:block md:w-auto';
    }, [stickyHeader]);

    return (
        <div className="test" style={{ height: 2000 }}>
            <div className={stickyClassName}>
                <NavbarTop sticky={stickyHeader} />
                {stickyMenu && <NavbarBottom sticky={stickyHeader} />}
            </div>
            <div>SmallNav</div>
        </div>
    );
};

export default Navbar;