user10302261
user10302261

Reputation:

React state change not causing re-render

I am trying to toggle the visibility of a div when clicking a seperate div. The problem is it sets the div invisible on the first click and only if it is visible to begin with. After that it just stays invisible and will not update. The state is still being toggled in the console however.

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  constructor(){
    super()
    this.state = {
      vis: '0'
    }
  }

  toghide=()=>{
    console.log("toggle login", this.state.vis)
    if(this.state.vis === "hidden"){
      console.log('showing')
      this.setState((state, props)=>({vis:'0'}))
    } else {
      console.log('hiding')
      this.setState((state, props)=>({vis:'hidden'}))
    }
  }

  render() {

    const styles = {
      visibility: this.state.vis
    }

    return (
      <div className="App">
        <div className="salebar"><a className="salebar sale" 
href="login">Click here!</a></div>
        <div className="navbar">
            <div className="nav"><div className="nnav">JMZ</div></div>
            <div className="nav2"><div className="nnav2">PRODUCTS</div></div>
            <div className="loginContainer"><div className="login" onClick={this.toghide}>LOGIN/SIGN UP</div></div>
        </div>
        <div className="login-container">
          <div className="lognester">
            <div style={styles} className="login-tab">
              <input className="user" type="text" placeholder="Username"/>
              <input className="password" type="password" placeholder="Password"/>
              <button className="user">Login</button>
          Sign in or <a className="register-link" href="register">register</a> a new account.
            </div>
          </div>
        </div>
        <div className="intro-pics"></div>
        <div className="content"></div>

        <audio preload loop controls autoPlay className="audio">
          <source src="https://memefly.me/i/toValhalla.mp3"/>
            Your browser does not support the audio element.
        </audio>
      </div>
    );
  }
}


export default App;

Upvotes: 0

Views: 457

Answers (3)

Tu Nguyen
Tu Nguyen

Reputation: 10179

Try this:

class App extends Component {
  constructor() {
    super();
    this.state = {
      vis: true
    };
  }
  toghide = () => {
    this.setState({ vis: !this.state.vis });
  };
  render() {
    return (
      <div className="App">
        <div className="salebar">
          <a className="salebar sale" href="login">
            Click here
          </a>
        </div>
        <div className="navbar">
          <div className="nav">
            <div className="nnav">JMZ</div>
          </div>
          <div className="nav2">
            <div className="nnav2">PRODUCTS</div>
          </div>
          <div className="loginContainer">
            <div className="login" onClick={this.toghide}>
              LOGIN/SIGN UP
            </div>
          </div>
        </div>
        <div className="login-container">
          <div className="lognester">
            {this.state.vis ? (
              <div className="login-tab">
                <input className="user" type="text" placeholder="Username" />
                <input
                  className="password"
                  type="password"
                  placeholder="Password"
                />
                <button className="user">Login</button>
                Sign in or{' '}
                <a className="register-link" href="register">
                  register
                </a>{' '}
                a new account.
              </div>
            ) : (
                ''
              )}
          </div>
        </div>
        <div className="intro-pics" />
        <div className="content" />
      </div>
    );
  }
}
export default App;

This is the demo: https://codesandbox.io/s/72zzk2xr70

Upvotes: 1

Harvey
Harvey

Reputation: 572

1 ) You can declare your togHide method above render such as

toghide = () => {
//your code
}

render(){...}

2) You may handle visibility condition better if you just use true/false boolean logic on your vis state. This can be as :

 constructor(){
        super()
        this.state = {
          vis: true
        }
      }


toghide = () => {

if(this.state.vis){

this.setState({
vis : false

})}

else{
this.setState({
vis : true
})}

3) In toghide method, you can use the code for setState I've used above. You don't have to pass props if you don't use any, and don't need to use return in setState.

Upvotes: 0

Doyin Olarewaju
Doyin Olarewaju

Reputation: 96

Two things are wrong with your code

  1. It should be visibility:visible not visibility: 0. So change that.
  2. Never ever ever ever... set state in your render function, really really bad practice.

Upvotes: 0

Related Questions