简体   繁体   中英

How do I return to previous state in reactjs?

I have created a sidebar component and set its state to false to hide the block until a user clicks on the hanmburger icon, then the state is shown. However I am trying to return(or close the sidebar menu) when the user clicks on the close 'X' icon. I have written a hideMenu method to return the state to false however it doesnt work, and there are no errors. Here is what I have written

class SubMainNavbar extends React.Component{
  constructor(){
    super();
    this.state = {isShown:false}
    this.showMenu = this.showMenu.bind(this)
    this.hideMenu = this.hideMenu.bind(this)
  }

  showMenu(){
    this.setState({isShown: true})
  }

  hideMenu(){
   this.setState({isShown: false})
  }
  render() {
    return (
      <div className="sub-flex-container">
        <div className="co pt-4">
      <ul className="flex-container sub-list">
        <li>women</li>
        <li>mens</li>
        <li>health & beauty</li>
      </ul>
      <span onClick={this.showMenu} className="pl-3 hamburger hide-big pb-4"><Icon type="menu" />
      <div className="mobile-menu-display" id="mySidebar" style={{display: this.state.isShown ? 'block' : 'none' }}>
        <span onClick={this.hideMenu} className="float-right font-weight-bold hide-big close">X</span>
      </div>
      </span>

    </div> 

    <div className="co">
    {/* <a href=""><Logo className="logo" /></a> */}
    <a href=""><img className="img-fluid logo" src={Logo} alt="losode logo"/></a>
    </div>

    <div className="co pt-4">
    <span className="hide-small"><SearchInput /></span>
    <div className="icon-mobile hide-big">
      <ul className="flex-icon sub-flex-container">
        <li><ion-icon name="search-outline"></ion-icon></li>
        <li><ion-icon name="person-outline"></ion-icon></li>
      <li><ion-icon name="basket-outline"></ion-icon></li>
      </ul>
    </div> 
    </div>

    </div>
    );
  }
};

export default SubMainNavbar

You didn't close your tags properly. update your code as per below:

  <div className="sub-flex-container">
        <div className="co pt-4">
      <ul className="flex-container sub-list">
        <li>women</li>
        <li>mens</li>
        <li>health & beauty</li>
      </ul>
      <span onClick={this.showMenu} className="pl-3 hamburger hide-big pb-4"><Icon type="menu" /></span>
      <div className="mobile-menu-display" id="mySidebar" style={{display: this.state.isShown ? 'block' : 'none' }}>
        <span onClick={this.hideMenu} className="float-right font-weight-bold hide-big close">X</span>
      </div>
      </div>


    <div className="co">
...

Your span, which you click to hide the menu, is inside the span, which triggers the showMenu function. You need to call the hideMenu function with the event parameter and use the stopPropagation function in your hideMenu function before setting the state. So the click of the span outside is not triggert and just the inner span will receive the click.

class SubMainNavbar extends React.Component{
  constructor(){
    super();
    this.state = {isShown:false}
    this.showMenu = this.showMenu.bind(this)
    this.hideMenu = this.hideMenu.bind(this)
  }

  showMenu(){
    this.setState({isShown: true})
  }

  hideMenu(event){
   event.stopPropagation()
   this.setState({isShown: false})
  }
  render() {
    return (
      <div className="sub-flex-container">
        <div className="co pt-4">
      <ul className="flex-container sub-list">
        <li>women</li>
        <li>mens</li>
        <li>health & beauty</li>
      </ul>
      <span onClick={this.showMenu} className="pl-3 hamburger hide-big pb-4"><Icon type="menu" />
        <div className="mobile-menu-display" id="mySidebar" style={{display: this.state.isShown ? 'block' : 'none' }}>
          <span onClick={event => this.hideMenu(event)} className="float-right font-weight-bold hide-big close">X</span>
        </div>
      </span>

    </div> 

    <div className="co">
    {/* <a href=""><Logo className="logo" /></a> */}
    <a href=""><img className="img-fluid logo" src={Logo} alt="losode logo"/></a>
    </div>

    <div className="co pt-4">
    <span className="hide-small"><SearchInput /></span>
    <div className="icon-mobile hide-big">
      <ul className="flex-icon sub-flex-container">
        <li><ion-icon name="search-outline"></ion-icon></li>
        <li><ion-icon name="person-outline"></ion-icon></li>
      <li><ion-icon name="basket-outline"></ion-icon></li>
      </ul>
    </div> 
    </div>

    </div>
    );
  }
};

export default SubMainNavbar

ps: You can use arrow functions so you don't need to use a constructor.

For example:

  this.state = { isShown: false }


  showMenu = () => {
    this.setState({isShown: true})
  }

  hideMenu = event => {
   event.stopPropagation()
   this.setState({isShown: false})
  }

You need to ensure that the event is not passed again to the outer container. In your case the event is triggered by the inner element which leads to a hideMenu but afterward the event is propagated to the outer container which leads to a recall of showMenu.

Additional reading about the can be found here: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation https://www.w3schools.com/jsref/event_stoppropagation.asp

Seems like Padi Dev also found the problem before me :)

really weird but could you try imitating what I did in this code sandbox? https://codesandbox.io/s/heuristic-fire-2jp8n?fontsize=14&hidenavigation=1&theme=dark

that should be as simple as it gets

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