Redirection to dashboard after login in react - reactjs

I have a login page, and I want to redirect users to dashboard after the details are filled.
I have tried using history.push and redirect components but I couldn't redirect.
Login Page
class Login extends React.Component {
state = {
email: '',
password: '',
errors: {},
redirect: false
}
validateForm = () => {
let errors = {};
let formIsValid = true;
if(!this.state.email) {
formIsValid = false;
errors['email'] = 'Please enter email to continue';
}
if(!this.state.password) {
formIsValid = false;
errors['password'] = 'Please enter password to continue';
}
this.setState({
errors: errors
})
return formIsValid;
}
handleChange = (event) => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = (event) => {
event.preventDefault();
// console.log(this.state);
if(this.validateForm()) {
const loginData = {
email: this.state.email,
password: this.state.password
}
axios
.post('/users.json', loginData)
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
})
}
}
render() {
return (
<div className="container">
<form onSubmit={this.handleSubmit} className="white">
<h5 className="grey-text text-darken-3">Login</h5>
<div className="input-field">
<label htmlFor="email">Email</label>
<input type="email" id="email" onChange={this.handleChange} />
<p>{this.state.errors.email}</p>
</div>
<div className="input-field">
<label htmlFor="password">Password</label>
<input type="password" id="password" onChange={this.handleChange} />
<p>{this.state.errors.password}</p>
</div>
<div className="input-field">
<button onClick={this.redirectHandler} className="btn btn-primary">Login</button>
</div>
</form>
</div>
)
}
}
export default Login;
I want to redirect to other page once the form is submitted with the email and password.
I've been trying this for days but I couldn't find a solution.

import { withRouter } from 'react-router';
class Login extends React.Component {
state = {
email: '',
password: '',
errors: {},
redirect: false
}
validateForm = () => {
let errors = {};
let formIsValid = true;
if(!this.state.email) {
formIsValid = false;
errors['email'] = 'Please enter email to continue';
}
if(!this.state.password) {
formIsValid = false;
errors['password'] = 'Please enter password to continue';
}
this.setState({
errors: errors
})
return formIsValid;
}
handleChange = (event) => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = (event) => {
event.preventDefault();
// console.log(this.state);
if(this.validateForm()) {
const loginData = {
email: this.state.email,
password: this.state.password
}
axios
.post('/users.json', loginData)
.then(response => {
this.props.history.push("/dashboard");
console.log(response.data);
})
.catch(error => {
console.log(error);
})
}
}
render() {
return (
<div className="container">
<form onSubmit={this.handleSubmit} className="white">
<h5 className="grey-text text-darken-3">Login</h5>
<div className="input-field">
<label htmlFor="email">Email</label>
<input type="email" id="email" onChange={this.handleChange} />
<p>{this.state.errors.email}</p>
</div>
<div className="input-field">
<label htmlFor="password">Password</label>
<input type="password" id="password" onChange={this.handleChange} />
<p>{this.state.errors.password}</p>
</div>
<div className="input-field">
<button onClick={this.redirectHandler} className="btn btn-primary">Login</button>
</div>
</form>
</div>
)
}
}
export default withRouter(Login);

have some complain about your code.
first: for form validation and handling you dont need to use state,
there is a library called Formik which will help you a lot with
this.
second: if you are using redux to check user is logged in or
not you need to create a private route for routes which cannot be
accessible for public like here dashboard component.
third: to use history you need to wrap your
component inside withRouter HOC which will pass route props to your
component so you can use history or if your are using functional component you can use useHistory() hook.

Related

How to use ComponentWillReceieveProp in React Hooks

I am trying to convert a class component into a functional component with hooks, but i am having a challenge on how to use an equivalent lifecycle of ComponentWillReceiveProps.
Log in form : Class Component:
class Login extends Component {
constructor() {
super();
this.state = {
emial:"",
password: "",
errors: {}
};
}
componentDidMount() {
window.history.pushState(null, document.title, window.location.href);
window.addEventListener('popstate', function (event){
window.history.pushState(null, document.title, window.location.href);
});
}
componentWillReceiveProps(nextProps) {// want to replace with hook equivalent
if (nextProps.auth.isAuthenticated) {
this.props.history.push("/recruitcentral"); // push user to dashboard when they login
}
if (nextProps.errors) {
this.setState({
errors: nextProps.errors
});
}
}
onChange = e => {
this.setState({ [e.target.id]: e.target.value });
};
onSubmit = e => {
e.preventDefault();
const userData = {
email: this.props.username,
password: this.state.password
};
this.props.loginUser(userData);
};
render() {
const { errors } = this.state;
return (
<>
<Row>
<Col>
<div>
<h1>Login</h1>
<div className={styles.formWrapper}>
<form onSubmit={this.onSubmit} noValidate>
<div className="email">
<label htmlFor="email"></label>
<input
onChange={this.onChange}
value={this.state.email}
error={errors.email}
id="email"
type="email"
className={classnames("", {
invalid: errors.email || errors.emailnotfound
})}
/>
<div className="Input__line" />
<label htmlFor="email" >Enter your email</label>
<span className="red-text">
{errors.email}
{errors.emailnotfound}
</span>
</div>
<div className="input-field col s12">
<input
onChange={this.onChange}
value={this.state.password}
error={errors.password}
id="password"
type="password"
className={classnames("", {
invalid: errors.password || errors.passwordincorrect
})}
/>
<div className="Input__line" />
<label htmlFor="password">Password</label>
<span className="red-text">
{errors.password}
{errors.passwordincorrect}
</span>
</div>
<div className={styles.createAccount}>
<button type="submit">Log in</button>
</div>
<div className={styles.createAccount}>
<button onClick={()=> this.props.history.push("/register")}type="submit">Create Account</button>
</div>
</form>
</div>
</div>
</Col>
</Row>
</>
Login Form :Functional Component
function Login(props) {
const [inputs, setInputs] = useState({
email:'',
password: '',
errors: {}
});
const [submitted, setSubmitted] = useState(false);
const { username, password } = inputs;
const auth =useSelector(state=>state.auth)
const dispatch = useDispatch();
const location = useLocation();
// reset login status
useEffect(() => {
dispatch(logoutUser());
}, []);
useEffect(() => {
// code to perform same function as componentWillReceiveProps here
}
}, [])
I know useEffect() will be used, but i really dont know how to implement it
componentWillRecieveProps is for all practical purposes deprecated with the recommendation being to use the componentDidUpdate lifecycle method. useEffect hook with appropriate dependency is the functional component equivalent.
For the first side-effect, navigating to "/recruitcentral" when user is authenticated.
useEffect(() => {
if (auth.isAuthenticated) {
props.history.push("/recruitcentral");
}
}, [auth]); // <-- Note: may complain about missing dependency like `history`, you can add these

I need to pass a URL from a class component to another

here is my QR component :
import React, { Component } from "react";
class QR extends React.Component {
constructor(props) {
super(props);
}
render() {
const { catImageUrl } = this.props;
const qrUrl = `https://qrtag.net/api/qr_12.svg?url=${catImageUrl}`;
if (!catImageUrl) return <p>Oops, something went wrong!</p>;
return <img className="QR" src={qrUrl} alt="qrtag" />;
}
}
export default QR;
I need to pass the const qrURL to the next component Form.js to use it in ajax call to get its data and pass it to the next api request to send it to an email
class Form extends React.Component{
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
message: '',
}
}
const{qrUrl}=this.props;
FetchQRURL = () => {
fetch(`${qrUrl}`)
.then((response) => response.json())
.then((data) => {
this.setState({
message: data,
});
})
.catch((error) => console.log(error));
};
handleSubmit(e){
e.preventDefault();
axios({
method: "POST",
url:"http://localhost:3002/send",
data: this.state
}).then((response)=>{
if (response.data.status === 'success'){
alert("Message Sent.");
this.resetForm()
}else if(response.data.status === 'fail'){
alert("Message failed to send.")
}
})
}
resetForm(){
this.setState({name: '', email: '', message: ''})
}
render() {
return(
<div className="App">
<form id="contact-form" onSubmit={this.handleSubmit.bind(this)} method="POST">
<div className="form-group">
<label htmlFor="name">Name</label>
<input type="text" className="form-control" id="name" value={this.state.name} onChange={this.onNameChange.bind(this)} />
</div>
<div className="form-group">
<label htmlFor="exampleInputEmail1">Email address</label>
<input type="email" className="form-control" id="email" aria-describedby="emailHelp" value={this.state.email} onChange={this.onEmailChange.bind(this)} />
</div>
<div className="form-group">
<label htmlFor="message">Message</label>
<textarea className="form-control" rows="5" id="message" value={this.state.message} onChange={this.onMessageChange.bind(this)} />
</div>
<button type="submit" className="btn btn-primary" onClick="">Submit</button>
</form>
</div>
);
}
onNameChange(event) {
this.setState({name: event.target.value})
}
onEmailChange(event) {
this.setState({email: event.target.value})
}
onMessageChange(event) {
this.setState({message: event.target.value})
}
}
export default Form;
you can see I tried to pass it as props but it doesn't work
here I tried to pass it as props(in my app.js)
import React, { Component } from "react";
import RandomCat from "./RandomCat.js";
import QR from "./QR.js";
import Form from "./form.js";
class BooksApp extends Component {
state = {
showCatImage: false,
showQrCode: false,
catImageUrl: "",
};
handleFetchRandomImage = () => {
fetch("https://aws.random.cat/meow")
.then((response) => response.json())
.then((data) => {
this.setState({
catImageUrl: data.file,
showCatImage: true,
});
})
.catch((error) => console.log(error));
};
handleShowQrCode = () => {
this.setState({ showQrCode: true });
};
render() {
const { showCatImage, showQrCode, catImageUrl,qrUrl } = this.state;
return (
<div className="app">
<div className="first">
{/* The time below shows cat image if showCatImage === true and returns nothing if false */}
{showCatImage && <RandomCat catImageUrl={catImageUrl} />}
<button className="catButton" onClick={this.handleFetchRandomImage}>
Generate Cat
</button>
</div>
<div className="second">
{showQrCode && <QR catImageUrl={catImageUrl} qrUrl={qrUrl}/>}
<button className="QRButton" onClick={this.handleShowQrCode}>
Geanerate QR
</button>
</div>
<div>
<Form qrUrl={qrUrl}/>
</div>
</div>
);
}
}
export default BooksApp;
any idea how can I pass it to the Form.js?
You have to pull the constant qrUrl to the parent component which is BooksApp in your case.
Set it to the state and pass it down as props.
state = {
showCatImage: false,
showQrCode: false,
catImageUrl: "",
qrUrl: ""
};
handleFetchRandomImage = () => {
fetch("https://aws.random.cat/meow")
.then((response) => response.json())
.then((data) => {
this.setState({
catImageUrl: data.file,
showCatImage: true,
qrUrl: `https://qrtag.net/api/qr_12.svg?url=${data.file}` // Set it here
});
})
.catch((error) => console.log(error));
};
handleShowQrCode = () => {
this.setState({ showQrCode: true });
};
render() {
const { showCatImage, showQrCode, catImageUrl, qrUrl } = this.state;
return (
<div className="app">
<div className="first">
{/* The time below shows cat image if showCatImage === true and returns nothing if false */}
{showCatImage && <RandomCat catImageUrl={catImageUrl} />}
<button className="catButton" onClick={this.handleFetchRandomImage}>
Generate Cat
</button>
</div>
<div className="second">
{showQrCode && <QR catImageUrl={catImageUrl} qrUrl={qrUrl}/>}
<button className="QRButton" onClick={this.handleShowQrCode}>
Geanerate QR
</button>
</div>
<div>
<Form qrUrl={qrUrl}/>
</div>
</div>
);
}
}
export default BooksApp;
The just use it with this.props.qrUrl in your other components.

ReactJS - how can I handle notifications to user based on server response?

so I've been trying to figure out
how to handle some notifications/alerts to show users some information based on what they typed in for example login form.
const DoLogin = async (email, password) => {
const loginTeacher = await axios.post(
"http://localhost:3000/teachers/login",
{
email,
password
}
);
return loginTeacher;
};
class Login extends React.Component {
state = {
email: "",
password: "",
logged: false,
status: "",
errorMessage: ""
};
onEmailChange = e => {
this.setState({
email: e.target.value
});
};
onPassChange = e => {
this.setState({
password: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
DoLogin(this.state.email, this.state.password)
.then(res => {
localStorage.setItem("mysecrettoken", res.data.token);
this.setState({ teacher: res.data, logged: true, status: res.status });
alert("Successfully logged in");
})
.catch(err => {
alert("Unable to login in, user not found");
});
};
loginForm() {
return (
<div className="Login form">
<form onSubmit={this.onSubmit}>
<label htmlFor="email">
Email:
<input
type="text"
name="email"
value={this.state.email}
onChange={this.onEmailChange}
/>
</label>
<br />
<label htmlFor="password">
Hasło:
<input
type="password"
name="password"
value={this.state.password}
onChange={this.onPassChange}
/>
</label>
<br />
<input type="submit" value="Zaloguj" />
<input type="button" value="Dodaj nauczyciela" />
</form>
</div>
);
}
}
Now, whenever a user is able to login it shows alert with the message, but I don't think that's a good way to show user information.
Could you please help me with that? Some articles/libraries would be great. I've tried to implement react toast but I failed to do that.
You can store the details in the state (like you already do) and then access in the render method for conditional rendering if the user has logged in.
const DoLogin = async (email, password) => {
const loginTeacher = await axios.post(
"http://localhost:3000/teachers/login",
{
email,
password
}
);
return loginTeacher;
};
class Login extends React.Component {
state = {
email: "",
password: "",
logged: false,
status: "",
errorMessage: ""
};
onEmailChange = e => {
this.setState({
email: e.target.value
});
};
onPassChange = e => {
this.setState({
password: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
DoLogin(this.state.email, this.state.password)
.then(res => {
localStorage.setItem("mysecrettoken", res.data.token);
this.setState({ teacher: res.data, logged: true, status: res.status, showingMessage: true });
setTimeout(() => {
this.setState({ showingMessage: false })
}, 2000)
alert("Successfully logged in");
})
.catch(err => {
// update state with ERROR
this.setState({ error: err.message })
alert("Unable to login in, user not found");
});
};
loginForm() {
if (this.state.logged && this.state.showingMessage) {
return (<div>You've logged in as {this.state.teacher.name}</div>)
}
return (
<div className="Login form">
{/* display ERROR */}
{this.state.error && <span style="color:red">
There was an error during registration: {this.state.error}.
</span>}
<form onSubmit={this.onSubmit}>
<label htmlFor="email">
Email:
<input
type="text"
name="email"
value={this.state.email}
onChange={this.onEmailChange}
/>
</label>
<br />
<label htmlFor="password">
Hasło:
<input
type="password"
name="password"
value={this.state.password}
onChange={this.onPassChange}
/>
</label>
<br />
<input type="submit" value="Zaloguj" />
<input type="button" value="Dodaj nauczyciela" />
</form>
</div>
);
}
}
I don't know where your render method is, but basically just access the state. You can also set a timeout after you received the data, and add another property on the state, like showingMessage which will be true at first, and then in say 2s will be false, then your condition would be if (this.state.logged & this.state.showingMessage).

how do i use <redirect/> for redirecting to a different page after login authentication?

I am doing a project on Reactjs and I'm new to it. Its just been few days since i have been working on Reactjs. I want to redirect to a new page after successfull login authentication. I am using but its not working, and being new to reactjs i cant figure out where i am going wrong. My redirect condition being if both "valid" and "proceed" = false then it will redirect it to another page. The boolean values for "valid" and "proceed" comes from a http response and its working fine but redirect it not working. The page remains as it is.
My sigin component : SignInForm.js->
import React, { Component } from "react";
import { Link, Redirect } from "react-router-dom";
import axios from "axios";
class SignInForm extends Component {
state = {
email: "",
pass: "",
proceed: false,
valid: false
};
passwordChange = event => {
this.setState({ pass: event.target.value });
};
emailChange = event => {
this.setState({ email: event.target.value });
};
handleOperation = event => {
event.preventDefault();
const user = this.state.email;
const pwd = this.state.pass;
console.log(user + "|" + pwd);
this.setState({
loading: true
});
const data = {
user,
pwd
};
axios
.post("https://some end-point where i make my request", data)
.then(res => {
console.log(res);
this.setState({
proceed: res.data.proceed,
valid: res.data.valid
});
console.log(
"res pro= " + res.data.proceed + "| res val=" + res.data.valid
);
console.log(
"state pro=" +
this.state.proceed +
"|" +
"state val = " +
this.state.valid
);
if (!this.state.proceed && !this.state.valid) {
console.log(" In condition");
return <Redirect to="/Demo" />;
}
})
.catch(err => {
console.log(err);
});
};
render() {
return (
<div className="FormCenter">
<form className="FormFields">
<div className="FormField">
<label className="FormField__Label" htmlFor="email">
E-Mail Address
</label>
<input
type="email"
id="email"
className="FormField__Input"
placeholder="Enter your e-mail address"
name="email"
onChange={this.emailChange}
/>
</div>
<div className="FormField">
<label className="FormField__Label" htmlFor="password">
Password
</label>
<input
type="password"
id="password"
className="FormField__Input"
placeholder="Enter your password"
name="password"
onChange={this.passwordChange}
/>
</div>
<div className="FormField">
<button
className="FormField__Button mr-20"
onClick={this.handleOperation}
>
Sign In
</button>
<Link to="/" className="FormField__Link">
Create a new account
</Link>
</div>
</form>
</div>
);
}
}
export default SignInForm;`
Demo Component :Demo.js ->
import React, { Component } from "react";
class Demo extends Component {
render() {
return <h1>THIS IS A DEMO</h1>;
}
}
export default Demo;
Use Redirect in render as it is a component. Also make initial state for valid & proceed as strings instead of boolean (otherwise it'll always be redirecting, as initial state will be always be false for both) and update the redirection condition also to incorporate that.
import React, { Component } from "react";
import { Link, Redirect } from "react-router-dom";
import axios from "axios";
class SignInForm extends Component {
state = {
email: "",
pass: "",
proceed: "false",
valid: "false"
};
passwordChange = event => {
this.setState({ pass: event.target.value });
};
emailChange = event => {
this.setState({ email: event.target.value });
};
handleOperation = event => {
event.preventDefault();
const user = this.state.email;
const pwd = this.state.pass;
console.log(user + "|" + pwd);
this.setState({
loading: true
});
const data = {
user,
pwd
};
axios
.post("https://some end-point where i make my request", data)
.then(res => {
this.setState({
proceed: res.data.proceed,
valid: res.data.valid
});
})
.catch(err => {
console.log(err);
});
};
render() {
if ( this.state.proceed===false && this.state.valid===false) {
return <Redirect to="/Demo" />;
}
return (
<div className="FormCenter">
<form className="FormFields">
<div className="FormField">
<label className="FormField__Label" htmlFor="email">
E-Mail Address
</label>
<input
type="email"
id="email"
className="FormField__Input"
placeholder="Enter your e-mail address"
name="email"
onChange={this.emailChange}
/>
</div>
<div className="FormField">
<label className="FormField__Label" htmlFor="password">
Password
</label>
<input
type="password"
id="password"
className="FormField__Input"
placeholder="Enter your password"
name="password"
onChange={this.passwordChange}
/>
</div>
<div className="FormField">
<button
className="FormField__Button mr-20"
onClick={this.handleOperation}
>
Sign In
</button>
<Link to="/" className="FormField__Link">
Create a new account
</Link>
</div>
</form>
</div>
);
}
}
export default SignInForm;`
Hope this helps ! Happy coding.
Redirect is a component that needs to be rendered. Also setState is async and so its value may not update immediately.
import React, { Component } from "react";
import { Link, Redirect } from "react-router-dom";
import axios from "axios";
class SignInForm extends Component {
state = {
email: "",
pass: "",
proceed: false,
valid: false
};
passwordChange = event => {
this.setState({ pass: event.target.value });
};
emailChange = event => {
this.setState({ email: event.target.value });
};
handleOperation = event => {
event.preventDefault();
const user = this.state.email;
const pwd = this.state.pass;
console.log(user + "|" + pwd);
this.setState({
loading: true
});
const data = {
user,
pwd
};
axios
.post("https://some end-point where i make my request", data)
.then(res => {
console.log(res);
this.setState({
proceed: res.data.proceed,
valid: res.data.valid
});
console.log(
"res pro= " + res.data.proceed + "| res val=" + res.data.valid
);
console.log(
"state pro=" +
this.state.proceed +
"|" +
"state val = " +
this.state.valid
);
})
.catch(err => {
console.log(err);
});
};
render() {
if (!this.state.proceed && !this.state.valid) {
console.log(" In condition");
return <Redirect to="/Demo" />;
}
return (
<div className="FormCenter">
<form className="FormFields">
<div className="FormField">
<label className="FormField__Label" htmlFor="email">
E-Mail Address
</label>
<input
type="email"
id="email"
className="FormField__Input"
placeholder="Enter your e-mail address"
name="email"
onChange={this.emailChange}
/>
</div>
<div className="FormField">
<label className="FormField__Label" htmlFor="password">
Password
</label>
<input
type="password"
id="password"
className="FormField__Input"
placeholder="Enter your password"
name="password"
onChange={this.passwordChange}
/>
</div>
<div className="FormField">
<button
className="FormField__Button mr-20"
onClick={this.handleOperation}
>
Sign In
</button>
<Link to="/" className="FormField__Link">
Create a new account
</Link>
</div>
</form>
</div>
);
}
}
export default SignInForm;

How can I pass data using <Redirect> in react router v4?

The situation is that I use axios gain data from back-end and I want to redirect from current page to another page as well as passing some data.
How can I pass data when I use <Redirect> to redirect?
I am using code like below, and I can't get 'profile' at the destination page. No matter, this.props or this.state
I understand that using react-router-redux is a better choice.
import React, { Component } from 'react'
import axios from 'axios'
import { Redirect } from 'react-router'
export default class Login extends Component {
constructor(props) {
super(props)
this.state = {
email: '',
emailError: 'Please fill in email',
password: '',
passwordError: 'Please fill in password',
redirect: false,
profile: ''
}
this.handleEmail = (e) => {
var email = e.target.value
var emailError = ''
if (email === null)
emailError = 'Please fill in email'
this.setState({
email: email,
emailError: emailError
})
}
this.handlePassword = (e) => {
var password = e.target.value
var passwordError = ''
if (password === null)
passwordError = 'Please fill in password'
this.setState({
password: password,
passwordError: passwordError
})
}
this.handleSubmit = (e) => {
e.preventDefault()
if (this.state.emailError)
alert(this.state.emailError)
else if (this.state.passwordError)
alert(this.state.passwordError)
else {
axios.post('/user/login', {
email: this.state.email,
password: this.state.password
}).then(response => {
if (response.data !== 'fail') {
this.setState({
redirect: true,
profile: response.data
})
}
})
}
}
}
render() {
const { redirect, profile } = this.state
if (redirect)
return (<Redirect to={{
pathname: '/user/profile',
state: { referrer: this.state.profile }
}} />)
return (
<div className="content user">
<div className="container">
<div className="row">
<div className="col-xs-12">
<h1>Log In Your Tutor Profile</h1>
<form role="form" noValidate>
<div className="row">
<div className="col-xs-12">
<label htmlFor="email">Email</label>
<div className="form-group">
<input id="email" type="text" className="form-control" value={this.state.email} onChange={this.handleEmail} name="email" required/>
</div>
</div>
</div>
<div className="row">
<div className="col-xs-12">
<label htmlFor="password">Password</label>
<div className="form-group">
<input id="password" type="password" className="form-control" value={this.state.password} onChange={this.handlePassword} name="password" required/>
</div>
</div>
</div>
<div className="row">
<div className="col-xs-12">
<div className="form-group">
<button className="btn btn-primary submit" onClick={this.handleSubmit}>LOG IN YOUR PROFILE</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
)
}
}
The way you are passing your state to the Redirect is correct, the only place the problem should be is how you are accessing it. State can be accessed like this.props.location.state. However if you directly route to the path then state won't we available so you need to add a check
Access your state like
this.props.location.state && this.props.location.state.referrer

Resources