【问题标题】:removeEventListener doesn't work on Modal closeremoveEventListener 在模态关闭时不起作用
【发布时间】:2021-06-23 19:17:20
【问题描述】:

我正在构建一个使用 Semantic UI React 的 React 应用程序。我有一些打开到模态组件的缩略图,以在模态中显示全尺寸图像。我还有用于浏览下一个和上一个的按钮。除了单击按钮外,我还想使用箭头键进行导航。当模式打开时,我可以将事件侦听器添加到窗口。但是当我关闭模式并打开另一个模式时,一个重复的事件侦听器添加到窗口中。这意味着我需要在模式关闭时删除事件侦听器。但是,Semantic UI React Modal 组件的 onClose 和 onUnmount 属性不应用删除。我怎样才能让它申请?除 removeEventListener 之外的任何东西都可以在 onClose 或 onUnmount 中运行,但 removeEventListener 不会运行。

这是整个附件组件:

import React, { Fragment, useState } from 'react'
import { Button, Card, Modal, Image } from 'semantic-ui-react'
import parse from 'html-react-parser'
import { IMedia } from '../../app/models/media'

interface IProps {
    attachedMedia: IMedia, 
    gallery: IMedia[], 
    featured: boolean
}

const Attachment: React.FC<IProps> = ({ attachedMedia, gallery, featured }) => {
    const [open, setOpen] = useState(false)
    const [index, setIndex] = useState(gallery.indexOf(attachedMedia))
    const [disabledNext, setDisabledNext] = useState(false)
    const [disabledPrev, setDisabledPrev] = useState(false)

    const handlePrev = () => {
        if (index > 0) {
            setIndex(index - 1)
            setDisabledNext(false)
            if (index === 1) setDisabledPrev(true)
        } 
    }

    const handleNext = () => {
        if (index < gallery.length - 1) {
            setIndex(index + 1)
            setDisabledPrev(false)
            if (index === gallery.length - 2) setDisabledNext(true)
        }
    }

    const handleClose = () => {
        setIndex(gallery.indexOf(attachedMedia))
        setDisabledPrev(false)
        setDisabledNext(false)
        setOpen(false)
        window.removeEventListener('keydown', handleKeyPress)
    }

    const handleMount = () => {
        if (index === 0) setDisabledPrev(true)
        if (index === gallery.length - 1) setDisabledNext(true)
        window.addEventListener('keydown', handleKeyPress)
    }

    const handleKeyPress = (e: KeyboardEvent) => {
        console.log(e)
    }

    return (
        <Fragment>
            {featured ? 
                (attachedMedia.media_details.sizes.medium?.source_url !== undefined) ? 
                    <Image src={attachedMedia.media_details.sizes.medium.source_url} ui={false} onClick={() => {setOpen(true)}} />
                :
                    <Image src={attachedMedia.media_details.sizes.full.source_url} ui={false} onClick={() => {setOpen(true)}} />
            :
                <Card className="attachment"><Image src={attachedMedia.media_details.sizes.thumbnail.source_url} onClick={() => setOpen(true)} /></Card>
            }
            
            <Modal open={open} centered={false} onClose={handleClose} onMount={handleMount}>
                <Modal.Header>
                    {parse(gallery[index].title.rendered)}
                </Modal.Header>
                <Modal.Content image scrolling>
                    <Image src={gallery[index].media_details.sizes.full.source_url} wrapped fluid />
                    <Modal.Description>
                        {parse(gallery[index].description.rendered)}
                    </Modal.Description>
                </Modal.Content>
                <Modal.Actions>
                    <Button disabled={disabledPrev} onClick={handlePrev}>Previous image</Button>
                    <Button disabled={disabledNext} onClick={handleNext}>Next image</Button>
                </Modal.Actions>
            </Modal>
        </Fragment>
    )
}

export default Attachment

这里,handleClose 函数包含了 removeEventListener,但是尽管handleClose 中的其余代码可以有效地运行,但移除并没有应用到窗口。

我能够运行 removeEventListener 的唯一试验是在 handleKeyPress 函数中使用它。但这不是我想要的,它会在一键按下后移除监听器。只要模态打开,我希望能够按键。

当模态框关闭时如何让 removeEventListener 生效?

【问题讨论】:

标签: javascript reactjs keyboard-events semantic-ui-react removeeventlistener


【解决方案1】:

你可以使用useEffect钩子。

因此,您需要从 handleOpenhandleClose 常量中删除 add/remove eventListener。

示例:

React.useEffect(() => {
    if (open) window.addEventListener('keydown', handleKeyPress);
    else window.removeEventListener('keydown', handleKeyPress);
  }, [open]
);

当您打开模式时,您将open 状态设置为true。

这个effect 带有随着open 状态变化的触发器。

因此,当它打开时,您正在添加侦听器,而当它关闭时,您正在移除侦听器。

简单!

【讨论】:

  • 我无法解释为什么,您的建议似乎完全合乎逻辑,但结果与我在问题中解释的相同。关闭模式时,按键会一直被监听。如果我打开另一个图像,听到的按键是重复的。
  • 您能否在 StackBlitz 或 CodeSandbox 上创建您项目的最小场景?
  • 我已经结合你的建议和清理功能解决了这个问题,谢谢:stackoverflow.com/a/66830872/4457663
【解决方案2】:

我从this question 得到了一个解决方案。使用 useEffect 并在清理函数中删除事件侦听器为我提供了所需的结果。这是代码块:

useEffect(() => {
        if (open) window.addEventListener('keydown', handleKeyPress)

        return () => {
            window.removeEventListener('keydown', handleKeyPress)
        }
    }, [open])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 2017-09-23
    • 1970-01-01
    相关资源
    最近更新 更多