【问题标题】:How to add multiple event listeners for the same react component?如何为同一个 React 组件添加多个事件监听器?
【发布时间】:2020-04-06 10:30:21
【问题描述】:

如何以更可重用的方式在同一个组件中添加多个事件监听器?

  componentDidMount: function() {
    window.addEventListener('resize', this.handleVisible);
    window.addEventListener('scroll', this.handleVisible);
...
  },

  componentWillUnmount: function() {
    window.removeEventListener('resize', this.handleVisible);
    window.removeEventListener('scroll', this.handleVisible);
...

  },

【问题讨论】:

  • 您可以为此创建一个自定义挂钩。
  • window.addEventListener('resize scroll', this.handleVisible);

标签: javascript reactjs react-component


【解决方案1】:

你可以像这样创建一个自定义钩子:

import { useEffect } from 'react'

export const useResizeScroll = callback => {
  useEffect(() => {
    window.addEventListener('resize scroll', callback);
    return () => window.removeEventListener('resize scroll', callback);
  }, [callback]);
};

然后像这样在你的组件中实现它:

const MyComponent = () => {
  useResizeScroll(handleVisible)

  function handleVisible() { ... }

  return (...)
}

注意:

这将要求您转到组件的挂钩实现。

所以如果你使用this.state = { ... },你需要去学习如何使用 React 的 useState 钩子:React useState Hook

更新:

如果您希望挂钩更灵活,例如选择您希望组件挂钩的事件侦听器,那么您可以这样做:

export const useResizeScroll = (eventListener, callback) => {
  useEffect(() => {
    window.addEventListener(eventListener, callback);
    return () => window.removeEventListener(eventListener, callback);
  }, [callback]);
};

然后像这样实现它:

useResizeScroll('resize scroll', handleVisible)

更高级的用例:

您还可以通过使用 React Context 来改进您的自定义钩子。这是一个实现跟踪窗口宽度的钩子的示例。

import React, { createContext, useContent, useEffect, useState } from 'react'

const ViewportContext = createContext({ width: window.innerWidth })

export const ViewportProvider = ({ children }) => {
  const [width, setWidth] = useState(window.innerWidth)

  function handleResize() {
    setWidth(window.innerWidth)
  }

  useEffect(() => {
    window.addEventListener('resize', handleResize)
    return () => window.removeEventListener('resize', handleResize)
  }, [])

  return (
    <ViewportContext.Provider value={{ width }}>
      {children}
    </ViewportContext.Provider>
  )
}

export const useViewport = () => {
  const { width } = useContext(ViewportContext)
  return { width }
}

然后你可以像这样在任何组件中使用它:

const { width } = useViewport()

这应该为您提供足够的信息来构建自定义挂钩以匹配您的用例。

【讨论】:

  • 感谢您的回复。因此,如果还有其他事件侦听器,我可以简单地添加同一个钩子,但在组件中添加这样的? useResizeScroll(handleVisible); useResizeScroll(handlehidden) 如果还有其他回调的情况?
  • 我会更新使用不同事件监听器的用例。
  • 我有点困惑。所以我的问题是我是否可以用分号分隔不同的回调两次调用同一个钩子。这里也不应该是 return () => window.removeEventListener('eventlistener', callback);以及在更新的部分?
  • 是的,抱歉,我会解决的。为什么不将多个回调组合成一个函数并将其作为您的回调?
  • 回调是完全不同的,不幸的是没有办法将它们混合在一起。
【解决方案2】:

这个:

window.addEventListener('resize scroll', callback); 

对我没用。

我不得不这样做:

window.addEventListener('resize', callback);
window.addEventListener('scroll', callback);

但这有效:

window.removeEventListener('resize scroll', handleResize) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    • 2014-05-18
    • 2014-10-16
    • 2022-11-23
    相关资源
    最近更新 更多