Detect click outside React component

后端 未结 30 1675
日久生厌
日久生厌 2020-11-22 13:54

I\'m looking for a way to detect if a click event happened outside of a component, as described in this article. jQuery closest() is used to see if the target from a click e

30条回答
  •  忘掉有多难
    2020-11-22 14:17

    An example with Strategy

    I like the provided solutions that use to do the same thing by creating a wrapper around the component.

    Since this is more of a behavior I thought of Strategy and came up with the following.

    I'm new with React and I need a bit of help in order to save some boilerplate in the use cases

    Please review and tell me what you think.

    ClickOutsideBehavior

    import ReactDOM from 'react-dom';
    
    export default class ClickOutsideBehavior {
    
      constructor({component, appContainer, onClickOutside}) {
    
        // Can I extend the passed component's lifecycle events from here?
        this.component = component;
        this.appContainer = appContainer;
        this.onClickOutside = onClickOutside;
      }
    
      enable() {
    
        this.appContainer.addEventListener('click', this.handleDocumentClick);
      }
    
      disable() {
    
        this.appContainer.removeEventListener('click', this.handleDocumentClick);
      }
    
      handleDocumentClick = (event) => {
    
        const area = ReactDOM.findDOMNode(this.component);
    
        if (!area.contains(event.target)) {
            this.onClickOutside(event)
        }
      }
    }
    

    Sample Usage

    import React, {Component} from 'react';
    import {APP_CONTAINER} from '../const';
    import ClickOutsideBehavior from '../ClickOutsideBehavior';
    
    export default class AddCardControl extends Component {
    
      constructor() {
        super();
    
        this.state = {
          toggledOn: false,
          text: ''
        };
    
        this.clickOutsideStrategy = new ClickOutsideBehavior({
          component: this,
          appContainer: APP_CONTAINER,
          onClickOutside: () => this.toggleState(false)
        });
      }
    
      componentDidMount () {
    
        this.setState({toggledOn: !!this.props.toggledOn});
        this.clickOutsideStrategy.enable();
      }
    
      componentWillUnmount () {
        this.clickOutsideStrategy.disable();
      }
    
      toggleState(isOn) {
    
        this.setState({toggledOn: isOn});
      }
    
      render() {...}
    }
    

    Notes

    I thought of storing the passed component lifecycle hooks and override them with methods simillar to this:

    const baseDidMount = component.componentDidMount;
    
    component.componentDidMount = () => {
      this.enable();
      baseDidMount.call(component)
    }
    

    component is the component passed to the constructor of ClickOutsideBehavior.
    This will remove the enable/disable boilerplate from the user of this behavior but it doesn't look very nice though

提交回复
热议问题