Reactjs 防止eventListener多次触发

Reactjs 防止eventListener多次触发,reactjs,addeventlistener,higher-order-components,Reactjs,Addeventlistener,Higher Order Components,我正在创建一个HOC,它添加了在输入组件有任何锚定标记的情况下从外部打开超链接的功能 以下为特别报告: export const withExternalLink = ( Component, rootId = false ) => ( props ) => { function openLinksExternally( e, rootId ) { const rootHtml = e.target.closest( rootId ); if

我正在创建一个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 } />;
};
如果
在一个页面上使用一次,则此操作有效。但是如果我们使用它
n
次,那么
useffect()
将运行
n
次,这将添加事件侦听器
n

我可以通过将
openLinksExternally()
移动到
withExternalLink()
之外来解决这个问题,这样就只有一个函数引用。但问题是我必须使用匿名函数来添加事件侦听器,因为我必须将
rootId
参数传递给
openlinksexternaly()

由于我使用了匿名函数,因此会为每个
useffect()
注册一个新的事件侦听器,并且每当单击
标记时,
openlinksexternaly()
都会运行
n


有没有更好的方法来实现这一点,使单击只运行一次?

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

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 } />;
    };
};
export const with externallink=(组件)=>(rootId=false)=>{
设isListenerAttached=false;
返回(道具)=>{
函数OpenLinksExternaly(e,id){
如果(!id){
返回;
}
const rootHtml=e.target.closest(id);
如果(!rootHtml){
返回;
}
常量锚点=e.target.closest('a');
如果(锚定){
setAttribute('target','u blank');
}
}
useffect(()=>{
如果(!isListenerAttached){
document.addEventListener('click',(e)=>OpenLinksExternaly(e,rootId));
isListenerAttached=true;
返回;
}
return()=>document.removeEventListener('click',(e)=>openlinksexternaly(e,rootId));
}, [] );
返回;
};
};
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 } />;
    };
};