Rendering new component on click in react

All we need is an easy explanation of the problem, so here it is.

I’m practicing react and trying to render a new component on click of a button. Here the first page is email and the component i want to render contains password page.

  class App extends React.Component {
 passwordpage(){
    return(
      <form>
        <div className="mainapp">
          <h2> Password</h2>
          <input type='Password' className="inputpassword" placeholder='Enter Password' required/>
          <div>
            <button type="submit" className="loginbutton">Next</button>
          </div>
        </div>
      </form>
    );
  };

  render() {
    return (
      <form>
        <div className="mainapp">
          <h2>Email  Id</h2>
          <input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
          <div>
            <button type="submit" onClick={this.props.passwordpage} className="loginbutton">Next</button>
          </div>
        </div>
      </form>

    );
  }
}

 ReactDOM.render(<App/>,document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

The simplest is to have the password page already prepared in your render(),
and to show/hide it depending on the component state, that is mutated by the onClick handler, something along those lines:

showPasswordPage() {
  this.setState({showPassword: true });
}

render() {
  const passwordPage = (<form>
    <div className="mainapp">
      <h2> Password</h2>
      <input type='Password' className="inputpassword" placeholder='Enter Password' required/>
      <div>
        <button type="submit" className="loginbutton">Next</button>
      </div>
    </div>
  </form>);

  const mainForm = (<form>
    <div className="mainapp">
      <h2>Email  Id</h2>
      <input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
      <div>
        <button type="submit" onClick={this.showPasswordPage} className="loginbutton">Next</button>
      </div>
    </div>
  </form>);

  return { this.state.showPassword ? passwordPage : mainForm };

Method 2

I usually keep some variables in state and change them based on user action.

So in your case I have stored the current active page e.g usernamePage and when user clicks next I show another page in your case it is passwordPage.

class App extends React.Component {
  
  constructor(props) {
    super(props);

    this.state = {
      isPasswordPage : false,
      isUsernamePage : true,
      username       : "",
      password       : ""
    };

    this.enablePasswordPage  = this.enablePasswordPage.bind(this);
  }

  enablePasswordPage() {
    this.setState({
      isPasswordPage : true,
      isUsernamePage : false
    });
  }
  
  passwordpage(){
    return(
      <form>
        <div className="mainapp">
          <h2> Password</h2>
          <input type='Password' className="inputpassword" placeholder='Enter Password' required/>
          <div>
            <button type="submit" className="loginbutton">Next</button>
          </div>
        </div>
      </form>
    );
  };

  render() {
    var usernameComp = (
      <form>
        <div className="mainapp">
          <h2>Email  Id</h2>
          <input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
          <div>
            <button onClick={this.enablePasswordPage} className="loginbutton">Next</button>
          </div>
        </div>
      </form>
    );
    
    return (
      <div>
        { this.state.isUsernamePage ? usernameComp : null }
        { this.state.isPasswordPage ? this.passwordpage() : null }
      </div>
    );
  }
}

ReactDOM.render(<App/>,document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

Method 3

What you need to do is to make use of react-router and then create separate components for each of the Page that you want to display. That is the best possible way to achieve what you want to do.

You components will look something like

class Home extends React.Component {
    render() {
    return (
        <div>{this.props.children}</div>
    )
  }
}

class App extends React.Component {

  handleClick = (e) => {
     e.stopPropagation();
     browserHistory.push('/passwordPage');
  }
  render() {
    return (
      <form>
        <div className="mainapp">
          <h2>Email  Id</h2>
          <input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
          <div>
            <button className="loginbutton" onClick={this.handleClick}>Next</button>
          </div>
        </div>
      </form>

    );
  }
}

class PasswordPage extends React.Component {
    render() {
    return (
        <form>
        <div className="mainapp">
          <h2> Password</h2>
          <input type='Password' className="inputpassword" placeholder='Enter Password' required/>
          <div>
            <button type="submit" className="loginbutton">Next</button>
          </div>
        </div>
      </form>
    )
  }
}

ReactDOM.render(
   <Router history={browserHistory}>
   <Route path="/" component={Home}>
    <IndexRoute component={App} />
    <Route path="/passwordPage" component={PasswordPage} />
   </Route>
   </Router>
)

Look at the react-router docs here

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply