简体   繁体   中英

Change the state when clicking outside a component in React

I have a dropdown as is shown in the following image: 在此处输入图像描述

When I click the folder icon it opens and closes because showingProjectSelector property in the state that is set to false.

  constructor (props) {
    super(props)
    const { organization, owner, ownerAvatar } = props
    this.state = {
      owner,
      ownerAvatar,
      showingProjectSelector: false
    }
  }

When I click the icon, it opens and closes properly.

<i
  onClick={() => this.setState({ showingProjectSelector: !this.state.showingProjectSelector })}
  className='fa fa-folder-open'>
</i>

But what I'm trying to do is to close the dropdown when I click outside it. How can I do this without using any library?

This is the entire component: https://jsbin.com/cunakejufa/edit?js,output

您可以尝试利用onBlur

<i onClick={...} onBlur={() => this.setState({showingProjectSelector: false})}/>

I faced same issue with you. Solved after reading this: Detect click outside React component Please try:

You should use a High Order Component to wrap the component that you would like to listen for clicks outside it.

This component example has only one prop: "onClickedOutside" that receives a function.

ClickedOutside.js
import React, { Component } from "react";

export default class ClickedOutside extends Component {
  componentDidMount() {
    document.addEventListener("mousedown", this.handleClickOutside);
  }

  componentWillUnmount() {
    document.removeEventListener("mousedown", this.handleClickOutside);
  }

  handleClickOutside = event => {
    // IF exists the Ref of the wrapped component AND his dom children doesnt have the clicked component 
    if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
      // A props callback for the ClikedClickedOutside
      this.props.onClickedOutside();
    }
  };

  render() {
    // In this piece of code I'm trying to get to the first not functional component
    // Because it wouldn't work if use a functional component (like <Fade/> from react-reveal)
    let firstNotFunctionalComponent = this.props.children;
    while (typeof firstNotFunctionalComponent.type === "function") {
      firstNotFunctionalComponent = firstNotFunctionalComponent.props.children;
    }

    // Here I'm cloning the element because I have to pass a new prop, the "reference" 
    const children = React.cloneElement(firstNotFunctionalComponent, {
      ref: node => {
        this.wrapperRef = node;
      },
      // Keeping all the old props with the new element
      ...firstNotFunctionalComponent.props
    });

    return <React.Fragment>{children}</React.Fragment>;
  }
}

If you want to use a tiny component (466 Byte gzipped) that already exists for this functionality then you can check out this library react-outclick .

The good thing about the library is that it also lets you detect clicks outside of a component and inside of another. It also supports detecting other types of events.

Using the library you can have something like this inside your component.

import OnOutsiceClick from 'react-outclick';

class MyComp extends Component { 

  render() {
    return (
      <OnOutsiceClick
        onOutsideClick={() => this.setState({showingProjectSelector: false})}>
        <Dropdown />
      </OnOutsiceClick>
    );
  }
}

Wrapper component - ie the one that wrapps all other components

create onClick event that runs a function handleClick.

handleClick function checks ID of the clicked event.

When ID matches it does something, otherwise it does something else.

const handleClick = (e) => {

    if(e.target.id === 'selectTypeDropDown'){
        setShowDropDown(true)
    } else {
        setShowDropDown(false); 
    }


}

So I have a dropdown menu that appears ONLY when you click on the dropdown menu, otherwise it hides it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM