【问题标题】:Prevent eventListener from firing multiple times防止 eventListener 多次触发
【发布时间】:2021-05-11 14:31:09
【问题描述】:

如果输入组件有任何锚标记,我正在创建一个 HOC,它添加了从外部打开超链接的功能。

以下是 HOC:

export const withExternalLink = ( Component, rootId = false ) => ( props ) => {
    function openLinksExternally( e, rootId ) {
        const rootHtml = e.target.closest( rootId );

        if ( ! rootHtml ) {
            return;
        }

        const anchor = e.target.closest( 'a' );

        if ( anchor ) {
            e.preventDefault();

            /**
             * Logic to open link externally.
             */
        }
    }

    useEffect( () => {
        document.addEventListener( 'click', ( e ) => openLinksExternally( e, rootId ) );
        return () => document.removeEventListener( 'click', ( e ) => openLinksExternally( e, rootId ) );
    }, [] );

    return <Component { ...props } />;
};

用法:

const CardWithExternalLinks = withExternalLink( Card );

如果&lt;CardWithExternalLinks /&gt; 在页面上使用一次,则此方法有效。但是如果我们使用它n 次,那么useEffect() 运行n 次,然后添加事件监听器n 次。

我能够通过将openLinksExternally() 移到withExternalLink() 之外来解决它,这样只有1 个对该函数的引用。但问题是我必须使用匿名函数来添加事件监听器,因为我必须将rootId 参数传递给openLinksExternally()

由于我使用了匿名函数,因此为每个useEffect() 注册了一个新的事件侦听器,并且每当单击&lt;a/&gt; 标记时,openLinksExternally() 就会运行n 次。

有没有办法更好地实现这一点,以便点击运行一次?

【问题讨论】:

    标签: reactjs addeventlistener higher-order-components


    【解决方案1】:

    我用闭包解决了这个问题,这是我的解决方案:

    export const withExternalLink = ( Component ) => ( rootId = false ) => {
        let isListenerAttached = false;
    
        return ( props ) => {
            function openLinksExternally( e, id ) {
                if ( ! id ) {
                    return;
                }
    
                const rootHtml = e.target.closest( id );
    
                if ( ! rootHtml ) {
                    return;
                }
    
                const anchor = e.target.closest( 'a' );
    
                if ( anchor ) {
                    anchor.setAttribute( 'target', '_blank' );
                }
            }
    
            useEffect( () => {
                if ( ! isListenerAttached ) {
                    document.addEventListener( 'click', ( e ) => openLinksExternally( e, rootId ) );
                    isListenerAttached = true;
                    return;
                }
                return () => document.removeEventListener( 'click', ( e ) => openLinksExternally( e, rootId ) );
            }, [] );
    
            return <Component { ...props } />;
        };
    };
    

    【讨论】:

      猜你喜欢
      • 2018-05-31
      • 2020-08-10
      • 2021-03-22
      • 1970-01-01
      • 1970-01-01
      • 2017-07-05
      • 1970-01-01
      • 1970-01-01
      • 2022-07-20
      相关资源
      最近更新 更多