【问题标题】:Why does addEventListener and removeEventListener inside useEffect() require an arrow function?为什么 useEffect() 中的 addEventListener 和 removeEventListener 需要箭头函数?
【发布时间】:2021-03-26 05:50:14
【问题描述】:

如果用户滚动到顶部,我会尝试将 onTop 状态设置为 true,否则设置为 false。我尝试了以下方法。

function Test()
{
    const [ onTop, setOnTop ] = useState( true )

    const watchScroll = () =>
    {
        if ( window.scrollY < 100 ) setOnTop( true )
        else setOnTop( false )
    }

    useEffect(() => {
        window.addEventListener(`scroll`, watchScroll )
        return  window.removeEventListener(`scroll`, watchScroll )
    }, [ watchScroll ])

    return (

        <div>{ onTop ? `On Top` : `Not On top` }</div>

    )
}

上面的例子不起作用,但也没有抛出错误。

function Test()
{
    const [ onTop, setOnTop ] = useState( true )

    const watchScroll = () =>
    {
        if ( window.scrollY < 100 ) setOnTop( true )
        else setOnTop( false )
    }

    useEffect(() => {
        window.addEventListener(`scroll`, () => watchScroll() )
        return  window.removeEventListener(`scroll`, () => watchScroll() )
    }, [ watchScroll ])

    return (

        <div>{ onTop ? `On Top` : `Not On top` }</div>

    )
}

请注意,我在第二个参数函数中添加了一个箭头和大括号。上面的示例按预期工作。谁能解释为什么?非常感谢!

【问题讨论】:

  • 内联函数对 removeEventListener 不起作用。
  • 您也可以传递函数引用。 window.addEventListener("scroll", watchScroll);两者都有效

标签: javascript reactjs addeventlistener use-effect


【解决方案1】:

您的初始函数无法正常工作的原因是,在每次重新渲染时,都会创建该函数的一个新实例,而您之前的一个实例将被删除,因为您将该函数作为依赖项传递给 useEffect。此外,由于您没有在清理函数中执行window.removeEventListener,它会立即运行,从而导致侦听器立即被删除。

您可以通过以下方式解决它

function Test()
{
    const [ onTop, setOnTop ] = useState( true )

    const watchScroll = useCallback(() =>
    {
        if ( window.scrollY < 100 ) setOnTop( true )
        else setOnTop( false )
    }, []);

    useEffect(() => {
        window.addEventListener(`scroll`, watchScroll )
        return () => window.removeEventListener(`scroll`, watchScroll )
    }, [ watchScroll ])

    return (

        <div>{ onTop ? `On Top` : `Not On top` }</div>

    )
}

function Test()
{
    const [ onTop, setOnTop ] = useState( true )

   
    useEffect(() => {
        const watchScroll = () => {
           if ( window.scrollY < 100 ) setOnTop( true )
           else setOnTop( false )
       }

        window.addEventListener(`scroll`, watchScroll )
        return ()=> window.removeEventListener(`scroll`, watchScroll )
    }, [ ])

    return (

        <div>{ onTop ? `On Top` : `Not On top` }</div>

    )
}

另请注意,使用箭头函数,您的解决方案可以工作,因为removeEventListener 您需要传递相同的函数引用才能使其正常工作,如果您使用箭头函数,则侦听器不会清理,因此您的实施工作

【讨论】:

  • 准确解释。 ?
  • 很高兴能帮上忙
【解决方案2】:

如果你想清理你的效果,你需要返回一个函数。

useEffect(() => {
        window.addEventListener(`scroll`, watchScroll )
        return  () => window.removeEventListener(`scroll`, watchScroll )
}, [ watchScroll ])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-15
    • 2017-12-06
    • 1970-01-01
    • 2018-02-11
    • 1970-01-01
    • 2022-12-05
    • 2016-01-25
    • 2020-09-06
    相关资源
    最近更新 更多