简体   繁体   English

UseEffect 不会使用更新的状态

[英]UseEffect won't use updated state

I have a react function which is supposed to be my header.我有一个反应函数,它应该是我的标题。 This header shall change its background color after reaching a button on scroll.到达滚动按钮后,此标题应更改其背景颜色。

To do so I use a scroll event listener and track its position in relation to the button.为此,我使用滚动事件侦听器并跟踪其相对于按钮的位置。 This works fine for setTransparent(false) , but not for setTransparent(true) :这适用于setTransparent(false) ,但不适用于setTransparent(true)
Logging transparent inside of the listener returns true even after setting it to false inside of the first if-statement.即使在第一个 if 语句中将其设置为false后,在侦听器内部记录transparent也会返回true

How so?为何如此? What's the best practice here?这里的最佳做法是什么?

const [transparent, setTransparent] = useState(true);

useEffect(() => {
    const button = document.querySelector(".hero-button");

    window.addEventListener("scroll", () => {
        const {bottom} = button.getBoundingClientRect();

        if (transparent && bottom <= 0) {
            setTransparent(false);
        } else if (!transparent && bottom > 0) {
            setTransparent(true);
        }
    });
}, [])

Setting the dependency to transparent will make it work, but this will add even listener every time it updates.将依赖项设置为transparent将使其工作,但这会在每次更新时添加甚至侦听器。

Your transparent variable in the effect callback only references the value on the initial render, which is always true .效果回调中的transparent变量仅引用初始渲染上的值,该值始终为true You can fix it by re-adding the scroll listener whenever transparent changes, and return a cleanup function that removes the prior handler:您可以通过在transparent更改时重新添加滚动侦听器来修复它,并返回一个删除先前处理程序的清理函数:

useEffect(() => {
    const button = document.querySelector(".hero-button");
    const scrollHandler = () => {
        const { bottom } = button.getBoundingClientRect();

        if (transparent && bottom <= 0) {
            setTransparent(false);
        } else if (!transparent && bottom > 0) {
            setTransparent(true);
        }
    };
    window.addEventListener("scroll", scrollHandler);
    // DON'T FORGET THE NEXT LINE
    return () => window.removeEventListener("scroll", scrollHandler);
}, [transparent]);

Another option would be to use a ref instead of useState for transparent (or, in addition to useState if transparent changes needs to result in re-rendering).另一种选择是使用 ref 而不是useState来实现透明(或者,如果transparent更改需要导致重新渲染,则除了useState之外)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM