1

I'm trying to have my app redirect to 'home' once a user has logged in. I do have an onSubmitSignin function that evaluates the log in credentials(from a temporary on page database) and then runs onRouteChange function which is then supposed to change the route to 'home' but instead I get the error "this.setState is not a function".

enter image description here

New to react, there's definitely something I don't get here. Any insight would be really appreciated, thanks!

App.js code:

const initialState = {
    route: 'signin',
    isSignedIn: false
}


class App extends Component {

constructor(props){
    super(props);
    this.state = initialState;
}

onRouteChange (route) {
    if (route === 'signout') {
        this.setState({initialState});
    } else if (route === 'home') {
        this.setState({isSignedIn: true})
    }
    this.setState({route: route}) 
}


render () {
const { isSignedIn } = this.state;


return ( 
 <div className="App">
<Navigation onRouteChange={this.onRouteChange} />
{isSignedIn ? <Account /> : <Signin onRouteChange={this.onRouteChange}/> }
</div>
);
}
}
export default App;

Signin code:

et database = {
  email: 'test@gmail.com',
  password: 'test'
}

class Signin extends React.Component {
constructor(props){
    super(props);
    this.state = {
        signInEmail: '',
        signInPassword: ''
    }

}


onEmailChange = (event) => {
  this.setState({signInEmail: event.target.value})
}

onPasswordChange = (event) => {
  this.setState({signInPassword: event.target.value})
}

onSubmitSignIn = (e) => {
  e.preventDefault();
  if (this.state.signInEmail === database.email && this.state.signInPassword === database.password) {
    this.props.onRouteChange('home');
  } else {
    return (this.props.onRouteChange('signout'));
  }
}

render () {

  return (
    <div className="form">
    <form>
    <div className="form-group">
      <label htmlFor="email">Email address</label>
      <input onChange ={this.onEmailChange} type="email" className="form-control" id="email" aria-describedby="emailHelp" placeholder="Enter email"/>
    </div>
    <div className="form-group">
      <label htmlFor="password">Password</label>
      <input onChange ={this.onPasswordChange} type="password" className="form-control" id="password" placeholder="Password"/>
    </div>
    <div className="signInButton">
    <button onClick={this.onSubmitSignIn} type="submit" className="btn btn-secondary">Sign in</button>
    </div>
  </form>
  </div>
  )
}

}

export default Signin;
F4-E
  • 47
  • 6
  • Does this answer your question? [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Martin Horváth May 18 '20 at 08:44
  • Does this answer your question? [React this.setState is not a function](https://stackoverflow.com/questions/31045716/react-this-setstate-is-not-a-function) – glinda93 May 18 '20 at 08:47

3 Answers3

3

You need to bind the context of this of your onRouteChange function in constructor to your component otherwise this will be undefined.

constructor() {
 this.onRouteChange= this.onRouteChange.bind(this)
}

Or you can convert your function to an arrow function. Arrow function doesn't create it's own instance of this so it's this will point to your class.

onRouteChange = (route) => {
    if (route === 'signout') {
        this.setState({initialState});
    } else if (route === 'home') {
        this.setState({isSignedIn: true})
    }
    this.setState({route: route}) 
}
Atin Singh
  • 2,913
  • 2
  • 9
  • 19
1

It's issue of binding and losing scope :

Due to the below line you are losing scope of the this,

onRouteChange (route) {

Solution :

Either you can bind the function in constructor OR Use arrow function

// Either you can bind the function in constructor
constructor() {
 this.onRouteChange= this.onRouteChange.bind(this)
}

OR

// Use arrow function
onRouteChange = (route) => {

OR

// I am not 100% sure about this, but it will work
<Navigation onRouteChange={() => this.onRouteChange.bind(this)}
Vivek Doshi
  • 46,471
  • 9
  • 84
  • 100
0

You can simply add a anonymous function () => {} to the Navigation component method call like:

<Navigation onRouteChange={() => this.onRouteChange} />

or use:

<Navigation onRouteChange={this.onRouteChange.bind(this)} />

Now this refers to the Component where the function called belongs to.

Zuckerberg
  • 909
  • 1
  • 7
  • 18