I am a beginner in React and was implementing a function where on a button click in the render method, I go to a function foo. In that function, I am sending the username and password to a server.
If the username and password are correct, it returns a JSON object like
{"Result":1,"Cookie":"COOKIE!!!"}
Now, if the Result is 0, I want to print an error message saying invalid username and password and if it correct, I want to redirect it to a different component class. Can someone please help me?
I have tried reading a lot of posts but cannot do it. The issue is, I want to print something on the webpage but that can only be done in render. I am in a function foo when I get the cookie so I do not know how to print an error message.
I also do not know how to take it to a new page on successful authentication, ie, the cookie will be 1
import React from 'react';
import './style.scss';
import LoginImage from './LoginImage.png'
import Button from 'react-bootstrap/Button'
import Form from 'react-bootstrap/Form'
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
//import Logfailed from './Logfailed'
import Flood from './Flood'
class UserLogin extends React.Component {
constructor(props) {
super(props);
this.state = {userName:'', password:'', act:'l', flag:0};
this.handleChange1 = this.handleChange1.bind(this);
this.handleChange2 = this.handleChange2.bind(this);
this.handleClick = this.handleClick.bind(this);
}
async handleClick(e) {
const url = 'http://52.8.557.164/user'
const data = {username:this.state.userName, password:this.state.password, action:this.state.act};
try {
const response = await fetch(url,
{
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
});
const json = await response.json();
if(json['Result'] === 1) {
this.state.flag=1;
}
else {
this.state.flag=2;
}
console.log('Success', JSON.stringify(json));
console.log(json['Cookie']);
} catch (error) {
console.error('Error', error);
}
}
handleChange1(e) {
this.setState({userName: e.target.value})
}
handleChange2(e) {
this.setState({password: e.target.value})
}
render() {
const err = this.state.flag;
return (
<div className = 'outer-container' ref={this.props.containerRef}>
<div className = 'header'> Login </div>
<div className="content">
<div className="image">
<img src={LoginImage} />
</div>
<Form className = 'form'>
<Form.Group controlId="formBasicEmail" className = 'form-group'>
<Form.Label style={{marginTop: '90px'}}>Username</Form.Label>
<Form.Text className="text-muted" htmlFor="username"></Form.Text>
<input type="text" value = {this.state.userName} name="username" placeholder="username" onChange={this.handleChange1}/>
</Form.Group>
<Form.Group controlId="formBasicPassword" className = 'form-group'>
<Form.Label>Password</Form.Label>
<Form.Text className="text-muted" htmlFor="password"></Form.Text>
<input type="password" value = {this.state.password} name="password" placeholder="password" onChange={this.handleChange2} />
</Form.Group>
</Form>
</div>
<div className="footer">
<Button variant="outline-primary" size="lg" onClick={this.handleClick} className="btn" block>
Login
</Button>
</div>
</div>
);
}
}
export default UserLogin;
First off, in your handleClick() method, you are trying to directly modify your component's state instead of using React's built-in setState() method. This will prevent your UI from reacting to the update as React will have no way of knowing the state of your component has changed.
if(json['Result'] === 1) {
this.state.flag=1;
} else {
this.state.flag=2;
}
Instead, if you replace that code with:
if(json['Result'] === 1) {
this.setState({flag: 1});
} else {
this.setState({flag: 2});
}
Then this will cause your component to be re-rendered on each state change, and hence your app will become reactive.
Next, if you want to display a warning message to the user when the flag property is equal to 2, simply add a conditional expression in your JSX.
{ this.state.flag === 2 && <p>Your login credentials could not be verified, please try again.</p>}
What this means is that the <p>
tag will only be evaluated (hence rendered) if the first part of the expression, i.e. this.state.flag === 2
, evaluates to true.
If you want to redirect the user to another route upon successful login, simply import the Redirect
component from react-router-dom
and replace the return statement in your render() method with the following:
if (this.state.flag === 1) {
return <Redirect to='/route' />
}
// else
return (
<div className = 'outer-container' ref={this.props.containerRef}>
// ... add the rest of your JSX
)
For more info on this solution, please see this link.
So ultimately, your render() method could look something like the following:
render() {
if (this.state.flag === 1) {
return <Redirect to='/route' />
}
// else
return (
<div className = 'outer-container' ref={this.props.containerRef}>
<div className = 'header'> Login </div>
<div className="content">
<div className="image">
<img src={LoginImage} />
</div>
{ this.state.flag === 2 && <p>Your login credentials could not be verified, please try again.</p>}
// ... add the rest of your JSX
)
}
~~~ UPDATE ~~~
If the <Redirect>
approach does not work, there is another method we can try as well (also detailed here). We can redirect the user programatically after your fetch request resolves, assuming we get the correct flag back from the API. So you can try:
if(json['Result'] === 1) {
this.setState({ flag: 1 });
this.props.history.push('/route')
}
In order to use this approach, however, you will also need to wrap your component with the withRouter
HOF in your export statement. So instead of:
export default MyComponent
You will need to do:
export default withRouter(MyComponent)
Just make sure to import withRouter
from react-router-dom
.
If you take this approach, you will no longer need this block of code:
if (this.state.flag === 1) {
return <Redirect to='/route' />
}