How to Attach Drag & Drop Event Listeners to a React component
You don't need to use props. You can just add all the events inside your DropZone component.
http://codepen.io/jzmmm/pen/bZjzxN?editors=0011
This is where i add the events:
componentDidMount() { window.addEventListener('mouseup', this._onDragLeave); window.addEventListener('dragenter', this._onDragEnter); window.addEventListener('dragover', this._onDragOver); window.addEventListener('drop', this._onDrop); document.getElementById('dragbox').addEventListener('dragleave', this._onDragLeave); }
Your render method:
render() { return ( <div> {this.props.children} <div id="dragbox" className={this.state.className}> Drop a file to Upload </div> </div> ); }
As you can see in componentDidMount, i added an eventlistener to #dragbox as well. Because once you drag a file over the page, #dragbox is under the mouse cursor, so it needs a dragleave in case you decide you don't want to drop the file there.
Also, dragover
is needed to capture the drop
Then in my App component, i can use it like this:
class App extends React.Component { render() { return ( <DropZone> <div> <h1>Drag A File Here...</h1> </div> </DropZone> ); }}
Version of @mnsr's answer using styled-components library and React Hooks
const DragBox = styled.div(({ isVisible }: { isVisible }) => isVisible ? ` position: fixed; display: flex; border: 15px dashed white; width: 100%; height: 100%; z-index: 2000; top: 0; left: 0; right: 0; bottom: 0; flex: 1; justify-content: center; align-items: center; text-align: center; font-size: 30px; font-weight: 600; color: white; letter-spacing: 1px; margin: auto;` : 'display: none;');const DropZone = ({ children }) => { const [isVisible, setIsVisible] = useState(false); const onDragEnter = useCallback((e) => { setIsVisible(true); e.stopPropagation(); e.preventDefault(); return false; }, []); const onDragOver = useCallback((e) => { e.preventDefault(); e.stopPropagation(); return false; }, []); const onDragLeave = useCallback((e) => { setIsVisible(false); e.stopPropagation(); e.preventDefault(); return false; }, []); const onDrop = useCallback((e) => { e.preventDefault(); const files = e.dataTransfer.files; console.log('Files dropped: ', files); // Upload files setIsVisible(false); return false; }, []); useEffect(() => { window.addEventListener('mouseup', onDragLeave); window.addEventListener('dragenter', onDragEnter); window.addEventListener('dragover', onDragOver); window.addEventListener('drop', onDrop); return () => { window.removeEventListener('mouseup', onDragLeave); window.removeEventListener('dragenter', onDragEnter); window.removeEventListener('dragover', onDragOver); window.removeEventListener('drop', onDrop); }; }, [onDragEnter, onDragLeave, onDragOver, onDrop]); return ( <div> {children} <DragBox className="bg-secondary" isVisible={isVisible} onDragLeave={onDragLeave} > Drop files to Upload </DragBox> </div> );};