简体   繁体   中英

React dropdown that opens a unique div and closes the active one on click

What I want to happen is to show a corresponding div whenever I click on a link. None of the dropdowns should be visible on load. On click, the corresponding div should show and any open ones should close.

So when I click Dropdown1, the div for dropdown1 should show, and close any open divs from other dropdown.

constructor() {
    super();

    this.state = {
        showMenu: false,
    };

    this.showMenu = this.showMenu.bind(this);
    this.closeMenu = this.closeMenu.bind(this);
}

showMenu(event) {
    event.preventDefault();

    this.setState({ showMenu: true }, () => {
        document.addEventListener('click', this.closeMenu);
    });
}

closeMenu(event) {
    if (!this.dropdownMenu.contains(event.target)) {
        this.setState({ showMenu: false}, () => {
            document.removeEventListener('click', this.closeMenu);
        });
    }
}

render() {
    return (
        <div>
            <div onClick={this.showMenu}>Dropdown1</div>
            <div onClick={this.showMenu}>Dropdown2</div>
            <div onClick={this.showMenu}>Dropdown3</div>
            ...
            {/* Dropdown */}                
            {this.state.showMenu ? (
                <div                    
                    ref={(element1) => {
                        this.dropdownMenu = element1;
                    }}
                >
                    <div>
                       ...Dropdown content 1...
                    </div>
                </div>
            ) : null}
            {/* 2nd dropdown here*/}
            {this.state.showMenu ? (
                <div
                    ref={(element2) => {
                        this.dropdownMenu = element2;
                    }}
                >
                    <div>
                        ...Dropdown 2 Content...
                    </div>
                </div>
            ) : null}
           {/* 3rd dropdown here*/}
        </div>
    );
}

Basic idea would be to give a name to each of your menu, when dropdown is selected assign it to state variable for example selectedMenu and then in render() block do branching based on state's value.

this.state = {
  selectedMenu: null
}
...

clickCallback(name) {
   return () => this.setState({selectedMenu: name})
}

...
render() {

   ...
   <div onClick={this.clickCallback('dropdown1')}>Dropdown1</div>

   {this.dropdownMenu()}
    ...
}

dropdownMenu() {
   switch(this.state.selectedMenu) {
       case null:
          return null
       case 'dropdown1':
          return ..
       case 'dropdown2':
          return ....
   }
}
...

update:

to close the menu based on keyboard action or mouse click else where would need to add a global event listener on document object ( document.addEventListener() ) and set selectedMenu: null within event handler.

Adding global event listeners is commonly done within componentDidMount() lifecycle method of react element. When addEventListener() is used it's important to later also call document.removeEventLister() when it's no longer needed and in react this can be done in componentWillUnmount() lifecycle methodd. Though if app is small and component is used only once you probably won't notice any issues even if you don't remove event listeners, that said it is still a good habit to get used like it's good to get use to clean your dishes after done eating instead of waiting until it piles up and starts stinking.

   constructor() { 
     ...
   }
   componentDidMount() {  
      document.addEventListener('click', this.documentOnClick);
      document.addEventListener('keypress', this.onKeyPress);
   }
   componentWillUnmount() {
      docment.removeEventListener('click', this.documentOnClick);
      document.removeEventListener('keypress', this.onKeyPress);
   }
   documentOnClick = (event) => {
       this.setState({selectedMenu: null})
   }
   onKeyPress = (event) => {
       if(event.key === 'Escape') {
           this.setState({selectedMenu: null})
       }
   }

there might be some additional steps to be taken within documentOnClick(event){... } to ignore some events coming from you menu items.

npm install react-bootstrap bootstrap

import 'bootstrap/dist/css/bootstrap.min.css'; Component import React, { useState } from 'react'; import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';

   const Example = (props) => {
  const [dropdownOpen, setDropdownOpen] = useState(false);

  const toggle = () => setDropdownOpen(prevState => !prevState);

  return (
   <Dropdown isOpen={dropdownOpen} toggle={toggle}>
   <DropdownToggle caret>
    Dropdown
    </DropdownToggle>
    <DropdownMenu>
    <DropdownItem header>Header</DropdownItem>
    <DropdownItem>Some Action</DropdownItem>
     <DropdownItem>Quo Action</DropdownItem>
    </DropdownMenu>
   </Dropdown>
  );
  }

export default Example;

Set an onClick on the DropdownItem that closes the dropdown.

//put this before your return statement

const closeDropDown = () => {
       setDropdownItem(false)
    }

    <DropdownItem onClick={closeDropDown }} header>Header</DropdownItem>

You can see it accepts the onClick function here

https://reactstrap.github.io/components/dropdowns/

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