I would like to make my spinner appear upon the user clicking login. I'm checking to see if loading is true in login() method. If it is, make the spinner appear. I've been struggling with this for hours, can't see what am I doing wrong.
What am I doing wrong and how can I fix it?
import React, {Component} from 'react';
import fire from '../../config/Fire';
import classes from './Login.css';
import Spinner from '../../UI/Spinner/Spinner';
import { Link } from 'react-router-dom';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
loading: false
};
this.login = this.login.bind(this);
this.handleChange = this.handleChange.bind(this);
this.signup = this.signup.bind(this);
}
handleChange(e) {
this.setState({[e.target.name]: e.target.value});
}
login() {
fire.auth().signInWithEmailAndPassword(this.state.email, this.state.password).then((u) => {
}).catch((error) => {
console.log(error);
});
this.setState({loading: true});
if(this.state.loading) {
return(
<Spinner/>
);
}
}
signup(e) {
e.preventDefault();
fire.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).then((u) => {
}).then((u) => {
console.log(u)
})
.catch((error) => {
console.log(error);
})
}
render() {
return (
<div className={classes.Middle}>
<div className="form-group">
<h1>Email address</h1>
<input value={this.state.email} onChange={this.handleChange} type="email" name="email"
className="form-control" placeholder="Enter email"/>
</div>
<div className="form-group">
<h1>Password</h1>
<input value={this.state.password} onChange={this.handleChange} type="password" name="password"
className="form-control" placeholder="Password"/>
</div>
<Link to={{
pathname: '/ChooseTruck'
}}>
<button type="submit" onClick={this.login.bind(this)} className="btn btn-primary">Login</button>
</Link>
<button onClick={this.signup}>Signup</button>
</div>
);
}
}
export default Login;
I see what your problem is, you are trying to return the loader in the login function which is doable, but not with your current implementation. What I would suggest you do is to put the <Spinner /> component into the return of the render and only show it when the state is loading.
Something like this:
render() {
return (
this.state.loading ? <Spinner /> : <div> rest of your code </div>
)
}
Here you are saying, if the state of loading is true, then render the spinner, otherwise show the rest of the page. This is a much better approach for what you are trying to accomplish.
You can also remove the peace of code from the login function that returns the Spinner component.
if(this.state.loading) {
return(
<Spinner/>
);
}
Hit me up if you have any questions.
Hope this helps. :)
login should be a non-render method which makes your login request, it happens on an event. Your loading spinner should go in the render method (or a function called by it).
login() {
this.setState({loading: true});
fire.auth().signInWithEmailAndPassword(this.state.email, this.state.password)
.then((u) => {
console.log(u);
})
.catch(console.error)
.then(() => this.setState({loading: false}))
}
render() {
return (
<div className={classes.Middle}>
<div className="form-group">
<h1>Email address</h1>
<input value={this.state.email} onChange={this.handleChange} type="email" name="email"
className="form-control" placeholder="Enter email"/>
</div>
<div className="form-group">
<h1>Password</h1>
<input value={this.state.password} onChange={this.handleChange} type="password" name="password"
className="form-control" placeholder="Password"/>
</div>
<Link to={{
pathname: '/ChooseTruck'
}}>
<button type="submit" onClick={this.login.bind(this)} className="btn btn-primary">Login</button>
</Link>
<button onClick={this.signup}>Signup</button>
{this.state.loading && <Spinner/>}
</div>
);
}
Related
I am using React to build a web app. And when I click the login button and make a http request, my localhost link will add "?" in the end.
My server works fine on the postman app, but would actually give a 204 as a response to my login request. So my login wouldn't work at the moment.
Below is my code for "Login.js"
My apologies for any confusion I've made.
Thank you for your help in advance.
enter code here
import React from "react";
import { Link, withRouter } from "react-router-dom";
import "./Login.css";
import axios from "axios";
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
errorMessage: "",
isLoggedin: false,
};
this.handleInputValue = this.handleInputValue.bind(this);
// this.handleLogin = this.handleLogin.bind(this);
}
handleInputValue = (key) => (e) => {
this.setState({ [key]: e.target.value });
}
handleLogin = () => {
const { email, password } = this.state;
// if (!this.state.email || !this.state.password) {
// this.setState({ errorMessage: "Please check your email and password again." });
// } else {
axios.post("https://server.slowtv24.com/login",
{ email: email, password: password },
{ withCredentials: true }
)
.then((res) => {
console.log("login post res>>>", res);
// this.setState({
// isLoggedin: true,
// })
})
// }
}
render() {
return (
<div>
<div className="login">
<div className="login-half left">
<form>
<input type="text" placeholder="Enter email address" onChange={this.handleInputValue("email")} />
<input type="password" placeholder="Enter password" onChange={this.handleInputValue("password")} />
<button onClick={this.handleLogin}>Login</button>
</form>
</div>
<div className="bar bar-top"></div>
<span className="login-or">OR</span>
<div className="bar bar-bottom"></div>
<div className="login-half right">
<button>Login with GitHub</button>
<button>Login with Gmail</button>
</div>
</div>
</div>
)
};
}
export default Login;
You don't need form tag for login form, because you are handling the submit action in onClick event.
render() {
return (
<div>
<div className="login">
<div className="login-half left">
<input type="text" placeholder="Enter email address" onChange={this.handleInputValue("email")} />
<input type="password" placeholder="Enter password" onChange={this.handleInputValue("password")} />
<button onClick={this.handleLogin}>Login</button>
</div>
<div className="bar bar-top"></div>
<span className="login-or">OR</span>
<div className="bar bar-bottom"></div>
<div className="login-half right">
<button>Login with GitHub</button>
<button>Login with Gmail</button>
</div>
</div>
</div>
)
};
Regarding the question mark, you can add type="button" to your button.
Check this for more information.
Good evening,
I have a component that changes based on the state of a modal on which it resides. I am attempting to return the component to its original state by returning the modal's state to its prior setting but it is not working. I know the state is changing back because the console tells me so but the notification component is not changing back to null when the state returns to default. How do I force the notification component to revert to null when the component's state changes?
My modal is below:
import React from 'react';
import { Modal, Button } from 'react-bootstrap';
import emailjs from 'emailjs-com';
import './emailModal.css';
class emailModal extends React.Component {
state = {
sent: false,
error: false
}
//these two methods are my attempt to reset the component after it changes
sentTimeoutMethod = () => {
setTimeout(this.setState({ sent: false }), 500);
setTimeout(this.props.cancelled, 700);
}
errorTimeoutMethod = () => {
setTimeout(this.setState({ error: false }), 1800);
setTimeout(this.props.cancelled, 2000);
}
handleSubmit = (e) => {
e.preventDefault();
emailjs.sendForm('default_service', 'template_Fo3IEDvY', e.target,'user_m4BBDdGwESsTJhnMIKqFP')
.then((result) => {
this.sentTimeoutMethod();
this.setState({ sent: true });
}).catch(
(error) => {
this.errorTimeoutMethod();
this.setState({ error: true });
});
};
render() {
let buttons = (
<React.Fragment>
<Button className="buttonSize send mr-1"
size="lg"
outline="true"
type="submit">
<i className="fa fa-paper-plane" aria-hidden="true"></i>
</Button>
<Button className="buttonSize cancel mr-1"
size="lg"
variant="secondary"
onClick={this.props.cancelled}>
<i className="fa fa-times" aria-hidden="true"></i>
</Button>
</React.Fragment>
);
let notification;
if (this.state.sent) {
notification = <p className="grey-text">Sent!</p>
} else if (this.state.error) {
notification = <p className="grey-text">Found and error: please let me know on Github or LinkedIn</p>
} else {
notification = null;
}
return (
<React.Fragment>
<Modal.Dialog
className="emailModal"
style={{
transform: this.props.show ? 'translateY(0)' : 'translateY(-100vh)',
opacity: this.props.show ? '1' : '0'
}}>
<Modal.Header>
<Modal.Title>Send me an email</Modal.Title>
</Modal.Header>
<Modal.Body>
<form id="emailFormId"
onSubmit={this.handleSubmit}
className="emailForm"
method="post"
>
<label
htmlFor="formName"
className="grey-text"
>
Your name
</label>
<input
type="text"
id="formName"
name="contactName"
className="form-control"
required
/>
<br />
<label
htmlFor="formEmail"
className="grey-text">
Your email
</label>
<input
type="email"
id="formEmail"
name="contactEmail"
className="form-control"
required
/>
<br />
<label
htmlFor="formMessage"
className="grey-text">
I look forward to hearing from you
</label>
<textarea type="text"
id="formMessage" name="contactMessage"
className="form-control"
rows="4"
required
/>
<div className="text-center mt-4">
{buttons}
{notification}
</div>
</form>
</Modal.Body>
</Modal.Dialog>
</React.Fragment>
);
}
};
export default emailModal;
this.props.cancelled just sets show=false for the modal component. If more code is required to answer my question please let me know.
Here is a stripped down version of the app that demonstrates the issue. You may have to rename a few raw files with a .js extension... for some reason my javascript sometimes won't keep their .js.
https://2qh47.csb.app/
Thanks in advance.
sentTimeoutMethod = () => {
let self = this;
setTimeout(self.setState({ sent: false }), 500);
setTimeout(self.props.cancelled, 700); }
I have a login/register app that is using a port 3000 and to_do_list app that using a port 3001. Login/register app is writting in react and to_do_list in node.js.
I would like to make a redirection to localhost:3001/todolist from localhost:3000/login (when I log in I would like to redirect a users to another page that using other port).
My login.js file looks like this:
import React, { Component } from 'react'
import { login } from './UserFunctions'
class Login extends Component {
constructor() {
super()
this.state = {
email: '',
password: '',
errors: {}
}
this.onChange = this.onChange.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
onSubmit(e) {
e.preventDefault()
const user = {
email: this.state.email,
password: this.state.password
}
login(user).then(res => {
if (res) {
this.props.history.push(`/todolist`)
}
})
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-6 mt-5 mx-auto">
<form noValidate onSubmit={this.onSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Please sign in</h1>
<div className="form-group">
<label htmlFor="email">Email address</label>
<input
type="email"
className="form-control"
name="email"
placeholder="Enter email"
value={this.state.email}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
value={this.state.password}
onChange={this.onChange}
/>
</div>
<button
type="submit"
className="btn btn-lg btn-primary btn-block"
>
Sign in
</button>
</form>
</div>
</div>
</div>
)
}}export default Login
How to redirect users to localhost:3001/todolist from localhost:3000/login ?
The port is part of what defines the origin, so you can't change it with history.push. if you want to change that, you actually do have to load a new page from it.
I have two components :
LoginForm which is used to render the form to login in the app
LoginPage which get the data entered in the LoginForm component and send it to a server
For the moment I would like to handle the form submit and the change of an input value. I read these two articles in the react official website to help me :
https://reactjs.org/docs/lifting-state-up.html
https://reactjs.org/docs/forms.html
But I still don't detect the submit and the change from the LoginPage component when I'm entering a value in LoginForm.
Can you help me to see where is my mistake ?
Thanks by advance.
My two components :
LoginPage.js
class LoginPage extends Component {
constructor(props) {
super(props);
this.state = {
login: true, //switch between Login and SignUp
email: '',
password: '',
firstName: '',
lastName: ''
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleSubmit(){
alert("SUBMIT");
}
handleInputChange(event) {
alert("YOUHOU");
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
alert("YEEEP");
}
render(){
return (
<div>
<div>
{this.state.login ?
<Login onSubmit={this.handleSubmit} onChange={this.handleInputChange}/>
:
<Register />
}
</div>
<a
onClick={() => this.setState({ login: !this.state.login })}
>
{this.state.login ? 'Besoin d\'un compte ?' : 'Déjà un compte ?'}
</a>
</div>
)
}
}
LoginForm.js
class LoginForm extends Component {
render(){
return (
<div>
<Card>
<form onSubmit={this.props.handleSubmit}>
<div>
<div>
<TextField name="email" floatingLabelText="Email" errorText="Champ obligatoire" type="text" onChange={this.props.handleInputChange}/>
</div>
<div>
<TextField name="password" floatingLabelText="Mot de passe" errorText="Champ obligatoire" type="password" onChange={this.props.handleInputChange} />
</div>
<CardActions>
<div>
<RaisedButton label="Se connecter" primary={true} type="submit" fullWidth />
</div>
</CardActions>
</div>
</form>
</Card>
</div>
);
}
}
handleInputChange is passed down to LoginForm as onChange prop and similarly handleSubmit is passed down by the name onSubmit and hence you need to use it like
class LoginForm extends Component {
render(){
return (
<div>
<Card>
<form onSubmit={this.props.onSubmit}>
<div>
<div>
<TextField name="email" floatingLabelText="Email" errorText="Champ obligatoire" type="text" onChange={this.props.onChange}/>
</div>
<div>
<TextField name="password" floatingLabelText="Mot de passe" errorText="Champ obligatoire" type="password" onChange={this.props.onChange} />
</div>
<CardActions>
<div>
<RaisedButton label="Se connecter" primary={true} type="submit" fullWidth />
</div>
</CardActions>
</div>
</form>
</Card>
</div>
);
}
}
I am pretty new to react/redux I am pretty confused with this simple form.My error state is always undefined eventhough I am getting the error data from node js server Without error data I can't set my state.
routes/users.js
import express from 'express';
import Validator from 'validator';
import isEmpty from 'lodash/isEmpty'
let router = express.Router();
function ValidateInput(data) {
let errors = {};
if(isEmpty(data.email)){
errors.email = 'This fiels is required'
}
if(!Validator.isEmail(data.email)){
errors.email = "Email is in Valid"
}
if(isEmpty(data.password)){
errors.password = 'This fiels is required'
}
if(isEmpty(data.passwordConfirmation)){
errors.passwordConfirmation = 'This fiels is required'
}
if(!Validator.equals(data.password,data.passwordConfirmation)){
errors.passwordConfirmation = "Password Must Macthc"
}
if(isEmpty(data.timezone)){
errors.timezone = 'This fiels is required'
}
return{
errors,
isValid:isEmpty(errors)
}
}
router.post('/',(req,res) => {
console.log(req)
const {errors,isValid} = ValidateInput(req.body);
if(!isValid){
res.status(400).json(errors)
}
});
export default router
SignupForm.js
import React from 'react';
import timezones from '../../data/timezone';
import map from 'lodash/map';
class SignupForm extends React.Component {
constructor(props){
super(props);
this.state = {
username:'',
email:'',
password:'',
passwordConfirmation:'',
timezone:'',
errors:{}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e){
this.setState({ [e.target.name]:e.target.value })
}
onSubmit(e){
e.preventDefault();
this.setState({ errors:{} });
this.props.userSignupRequest(this.state).then(function (data) {
console.log(data)//Nothing
// this.setState({
// errors:data
// })
})
}
render(){
console.log(this.state)
const options = map(timezones,(val,key) =>
<option key={val} value={val}>{key}</option>
);
return(
<form onSubmit={this.onSubmit}>
<h1>Join our community</h1>
<div className="form-group">
<label className="control-label">Username</label>
<input
type="text"
name="username"
className="form-control"
value={this.state.username}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">Email</label>
<input
type="text"
name="email"
className="form-control"
value={this.state.email}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">Password</label>
<input
type="password"
name="password"
className="form-control"
value={this.state.password}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">passwordConfirmation</label>
<input
type="password"
name="passwordConfirmation"
className="form-control"
value={this.state.passwordConfirmation}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">Time Zone</label>
<select
className="form-control"
name="timezone"
onChange={this.onChange}
value={this.state.timezone}
>
<option value="" disabled>Choose Your Timezone</option>
{options}
</select>
</div>
<div className="form-group">
<button className="btn btn-primary btn-lg">
SignUp
</button>
</div>
</form>
)
}
}
SignupForm.propTypes ={
userSignupRequest:React.PropTypes.func.isRequired
};
export default SignupForm
You need to use catch... so
onSubmit(e){
e.preventDefault();
this.setState({ errors:{} });
this.props.userSignupRequest(this.state)
.then(function (data) {
//Success here
})
.catch(({response}) => console.log(response.data)) //Here you get your errors
})
}