Deleting event listeners in dynamic React component

67 Views Asked by At

Asking advice on adding and deleting event listeners in dynamic react components.

So, I have a functional component that has a list of objects.

It is being rendered like so:

objectList.map( (item) => {
return ( 
    <div>
        <some-component with props.id = item.id>
        <some-bootstrap-icon>
    <div>
    )
            }

My goal is to do some actions when the user clicks the icon and drags the mouse around and stop those actions once the mouse is up. In those actions I need to understand how much the mouse has moved and what object from the list was "touched".

What do I have currently

const some_action = (event, id) => { 
    ... using event.movementX and id for some actions
}


const rendering_func = () => {
    return ( {
        objectList.map( (item) => {

            const wrapper = (event) => {
                some_action(event, item.id);
                }       

            return <...>
                <bootstrap-icon 
                onMouseDown={()=>
                    {window.addEventListener("mousemove", wrapper)}
                        }
                onMouseUp={()=>
                    {window.removeEventListener("mousemove", wrapper)}
                        }
                />
                <...>
                    } )

    } )
}

The event listener is being successfully added and the "some_action" func does its job. The problem is: the event listener is not being removed on Mouse Up.

Edit: Imagine the rotate icon in MS PowerPoint. When you click it, you can drag your mouse and the object will rotate. When you let go, the rotation stops. Basically I am trying to recreate the same functionality in terms of clicking, dragging and letting go of the icon. powerpoint example

1

There are 1 best solutions below

4
On BEST ANSWER

What you are doing is: registering a global (!) mouse move event listener when you start start "clicking" the object and unregister it when you release the mouse again. You can directly pass the wrapper as a parameter to the onMouseDown/onMouseMove/onMouseUp props of the bootstrap-icon like this:

const some_action = (id) => (event) => { 
    ... using event.movementX and id for some actions
}


const rendering_func = () => {
    return ( {
        objectList.map( (item) => {    
            const moveHandler = some_action(item.id);
            return <... key={item.id}>
                <bootstrap-icon 
                    onMouseDown={() => {
                        window.addEventListener("mousemove", moveHandler);
                        window.addEventListener("mouseup", () => window.removeEventListener("mousemove", moveHandler));
                    }}
                />
                <...>
         } )

    } )
}

EDIT: misunderstanding from my side. The mouse should be moveable around the whole screen (i.e. leaving the bounds of the icon). The mousemove event handler remains registered in the onMouseDown event handler, but the mouseup event handler is now registered globally as well.