Inam
Inam

Reputation: 241

how to Stop rerendering of entire component onChange event on input text field in reactJs

I m new to reactJs and i m creating user Authentication functionality. I have two components one is header which has navbar and it contains react-router routers and the other is login component which has two input fields ... The problem with login component is when i start typing in input field it loses focus after each character typed i know it is rerendering the whole component but i don't know how to solve this problem

header.js

    changeName = (e) => {
      this.setState({name : e.target.value})
    }
    changePass = (e) => {
      this.setState({password:e.target.value})
    }

    login = () => {
      var name = this.state.name;
      var  password = this.state.password

      var mysession;
      $.ajax({
        url : 'http://localhost:4000/login',
        type : "POST",
        data : {username:name,password:password},
        success : function(data){
          if(data == true){
        this.setState({sessionFlag:true})
        $('#home')[0].click();
          }
          else {
            this.setState({sessionFlag:false})
          }
        }.bind(this)
      })
    }
    render(){
const {name,password} = this.state;
    return (
          <Router>
          <div>
    <Route path="/login" exact component={()=><Login 
    onClickHandle={this.login.bind(this)} 
    onChangeName={this.changeName.bind(this)} 
    onChangePass={this.changePass.bind(this)} 
    name={name} 
    password = {password} />} />
    </div>
          </Router>
        )
    }

login.js

render(){
    return (
<form className="form-horizontal" method ="post">
 <input 
type="text" 
onChange={this.props.onChangeName} 
value={this.props.name}/>

 <input type="text"
onChange={this.props.onChangePass} 
value={this.props.password} />
<input type="button" 
value="Login" 
onClick={this.props.onClickHandle} />
</form>
)
}

Upvotes: 2

Views: 2603

Answers (1)

Ryan Cogswell
Ryan Cogswell

Reputation: 81016

The main issue is the manner in which you are specifying your Login component:

      <Route
        path="/login"
        exact
        component={() => (
          <Login
            onChangeName={this.changeName.bind(this)}
            onChangePass={this.changePass.bind(this)}
            name={this.state.name}
            password={this.state.password}
          />
        )}
      />

Using this syntax causes the child of the Route to look like a brand-new type of component with each rendering (since it will be a new arrow function instance each time) so the previous Login component will be completely unmounted and the new one mounted.

From https://reactrouter.com/web/api/Route/component:

When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop (below).

Here is an example using the render-func approach:

Header.js

import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Login from "./Login";
class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "", password: "" };
    this.changeName = this.changeName.bind(this);
    this.changePass = this.changePass.bind(this);
  }
  changeName = (e) => {
    this.setState({ name: e.target.value });
  };
  changePass = (e) => {
    this.setState({ password: e.target.value });
  };
  render() {
    return (
      <Router>
        <div>
          <div>
            <Link to="/login">Login</Link>
          </div>
          <Route
            path="/login"
            exact
            render={() => (
              <Login
                onChangeName={this.changeName}
                onChangePass={this.changePass}
                name={this.state.name}
                password={this.state.password}
              />
            )}
          />
        </div>
      </Router>
    );
  }
}
export default Header;

Edit Route component with props

Upvotes: 6

Related Questions