Redirect component doesn't change url (React) - reactjs

I am building Signup component which should redirect to the root path if user has passed all information.
However, Redirect component doesn't work for some reason, as url is not changed. On line 12 I am logging in renderRedirect and I can see this message in my console so I am inside renderRedirect method but, like I said, url stays the same localhost:3000/signupm instead of changing to localhost:3000/.
Any idea why?
import React from "react";
import { Redirect } from "react-router-dom";
class Signup extends React.Component {
state = {
password: "",
fullName: "",
email: ""
};
renderRedirect = () => {
console.log("in renderRedirect");
return <Redirect push to="/" />;
};
handleInputChange = e => {
const value = e.target.value;
const name = e.target.name;
this.setState({ [name]: value });
};
handleSignup = () => {
this.props.onSignup(
{
username: this.state.username,
password: this.state.password,
fullName: this.state.fullName,
email: this.state.email
},
() => this.renderRedirect()
);
};
render() {
return (
<div className="login-wrap">
<h2>Sign Up</h2>
<div className="form">
<input
type="text"
placeholder="Full Name"
name="fullName"
value={this.state.fullName}
onChange={this.handleInputChange}
/>
<input
type="email"
placeholder="Email address"
name="email"
value={this.state.email}
onChange={this.handleInputChange}
/>
<input
type="password"
placeholder="Password"
name="password"
value={this.state.password}
onChange={this.handleInputChange}
/>
<button onClick={this.handleSignup}>Sign up</button>
</div>
</div>
);
}
}
export default Signup;

I would omit the 'push' from the redirect component and see if that works. Otherwise, you could make use of the history object and use this.props.history.push('/') instead. If you don't have access to the routeProps, you can wrap your Signup Component with { withRouter } from 'react-router-dom'

Related

How to display data from an API in react js?

Here I have a login form that I created in react js. The API I'm using gives a response as "Successful Login" or "Authentication Failed. Unable to login" depending on whether the login credentials match or not. In the login form I'm using a react hook and axios.post to send the "name" and "password" to the API. How can I also print the response I'm getting back from the API?
Here is the Login.js component:
import React, { Component } from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import { Button, TextField } from "#mui/material";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
password: "",
};
}
changeHandler = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
submitHandler = (e) => {
e.preventDefault();
console.log(this.state);
axios
.post("http://localhost:8080/users/login", this.state)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
};
render() {
const { name, password } = this.state;
return (
<div>
<h1>Login Page</h1>
<form onSubmit={this.submitHandler}>
<TextField
name="name"
label="Enter Username"
color="secondary"
focused
size="small"
variant="outlined"
onChange={this.changeHandler}
id="name"
value={name}
type="text"
placeholder="Username"
className="form-control"
/>
<p />
<TextField
name="password"
label="Enter Password"
color="secondary"
focused
size="small"
variant="outlined"
onChange={this.changeHandler}
id="password"
value={password}
type="text"
placeholder="Password"
className="form-control"
/>
<p />
<Button type="submit" variant="contained">
Login
</Button>
</form>
</div>
);
}
}
export default Login;
And here is what the console shows:
{name: 'Mike', password: 'password1234'}
{data: 'Authentication Failed. Unable to login', status: 200, statusText: '', headers: AxiosHeaders, config: {…}, …}
{name: 'Mike', password: 'Pass1234'}
{data: 'Successful Login', status: 200, statusText: '', headers: AxiosHeaders, config: {…}, …}
Can I use another react hook to fetch the data? The API uses POST method so I'm not sure how to do that.
here is a very basic example of login page using hooks. In the login function, you should call the API you want and use the setResponse to display the response on the screen
const [Name, setName] = useState("");
const [Pass, setPass] = useState("");
const [Response, setResponse] = useState("");
const userChange = (event) => {
setName(event.target.value);
};
const passChange = (event) => {
setPass(event.target.value);
};
const login = () => {
// login using Name and Pass
setResponse("server response")
}
return (
<ThemeComponent>
<TextField label={"user"} onchange={userChange} />
<TextField label={"pass"} onchange={passChange} />
{Response}
<Button onClick={login} text="LOGIN">LOGIN</Button>
</ThemeComponent>
)

Keep getting max update exceeded error but cannot seem to find error in code

I have made forms like this before but I seem to be missing something in this one. I keep getting the error "maximum update depth exceeded error" but I dont see where I am goin wrong and I've spent too much time looking at it. I already tried to change my onChange to include an arrow because others have suggested to do so , but when that happens I cant type in the input boxes. like so
onChange={()=>this.handleChange("username")}
I should note that I only get the error when I try to register the user and not when I type into the input. Here is the full error as well.
at checkForNestedUpdates (react-dom.development.js:23804)
at scheduleUpdateOnFiber (react-dom.development.js:21836)
at Object.enqueueSetState (react-dom.development.js:12468)
at Router.Component.setState (react.development.js:366)
at react-router.js:75
at listener (history.js:156)
at history.js:174
at Array.forEach (<anonymous>)
at Object.notifyListeners (history.js:173)
at setState (history.js:562)
Here is my code, please help.
import React from "React"
class Splash extends React.Component{
constructor(props) {
super(props)
this.state = this.props.user;
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.props.clearErrors();
}
handleSubmit(event) {
event.preventDefault();
this.props.signUp(this.state);
}
handleChange(field) {
return (e) => {
this.setState({ [field]: e.currentTarget.value })
};
}
render() {
return (
<div className="splash-background">
<div className="modal-screeen">
<form className="modal" onSubmit={this.handleSubmit}>
<h2 className="welcom-text"></h2>
<input className="user-input" type="text" placeholder="Name" onChange={this.handleChange("name")} value={this.state.name}/>
<input className="user-input" type="text" placeholder="Email" onChange={this.handleChange("email")} value={this.state.email}/>
<input className="user-input" type="text" placeholder="Create Username" onChange={this.handleChange("username")} value={this.state.username}/>
<input className="user-input" type="password" placeholder="Create Password" onChange={this.handleChange("password")} value={this.state.password}/>
<button>Sign Up</button>
</form>
</div>
</div>
);
}
}
export default Splash
import { connect } from "react-redux";
import { signup, login, clearErrors } from "../../actions/session_actions.js";
import Splash from "./splash";
const mapStateToProps = ({ errors }) => {
return {
errors: errors.session,
user: {
username: "",
password: "",
name:"",
email: "",
},
};
};
const mapDispatchToProps = (dispatch) => {
return {
signUp: (user) => dispatch(signup(user)),
login: (user) => dispatch(login(user)),
clearErrors: () => dispatch(clearErrors()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Splash);
I believe the problem here is the implementation of redux and react state. If you're using redux to manage the form state then I don't think there is a need to also manage that same state with react.
Try something like this, but keep in mind this code isn't tested.
class Splash extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.props.clearErrors();
}
handleSubmit(event) {
event.preventDefault();
this.props.signUp(this.props.user);
}
handleChange(e) {
// here you would have another action to update redux state depending
// on which input has changed. You can grab the input name via e.target.name
}
render() {
return (
<div className="splash-background">
<div className="modal-screeen">
<form className="modal" onSubmit={this.handleSubmit}>
<h2 className="welcom-text"></h2>
<input
className="user-input"
type="text"
placeholder="Name"
name="name"
onChange={this.handleChange}
value={this.props.user.name}
/>
<input
className="user-input"
type="text"
placeholder="Email"
name="email"
onChange={this.handleChange}
value={this.props.user.email}
/>
<input
className="user-input"
type="text"
placeholder="Create Username"
name="username"
onChange={this.handleChange}
value={this.props.user.username}
/>
<input
className="user-input"
type="password"
placeholder="Create Password"
name="password"
onChange={this.handleChange}
value={this.props.user.password}
/>
<button>Sign Up</button>
</form>
</div>
</div>
);
}
}
export default Splash;
When it comes to form data, I find it's easier to manage just with react state. Generally redux is used to manage state that is shared across the whole application/multiple components.
The problem was actually in my route util file. I had an infinite loop of rerouting!

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;

Where to put proptypes validation?

Im my react application, Im in the refactoring phase. I want to separate redux part from the components. Im confused about where to put proptypes validation? Should the redux props be validated in the container file, and component props should be validated on the component? Or should the both prop types be handled on the component? Or in container? Here is my code.
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';
import { registerUser } from '../../../actions';
import { TextFieldGroup } from '../../../components/UI';
class RegisterScreen extends Component {
state = {
name: '',
email: '',
password: '',
password2: '',
errors: {}
};
componentDidMount() {
if (this.props.auth.isAuthenticated) {
this.props.history.push('./dashboard');
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
onChange = e => {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit = e => {
e.preventDefault();
const newUser = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
password2: this.state.password2
}
this.props.registerUser(newUser, this.props.history);
}
render() {
const { errors } = this.state;
return (
<div className='register'>
<div className='container'>
<div className='row'>
<div className='col-md-8 m-auto'>
<h1 className='display-4 text-center'>Sign Up</h1>
<p className='lead text-center'>
Create Your Developer Connector Account
</p>
<form noValidate onSubmit={this.onSubmit}>
<TextFieldGroup
className={errors.email}
placeholder="* Full Name"
name="name"
value={this.state.name}
onChange={this.onChange}
error={errors.name}
/>
<TextFieldGroup
type='email'
className={errors.email}
placeholder="* Email Address"
name="email"
value={this.state.email}
onChange={this.onChange}
error={errors.email}
info='This site uses Gravatar so if you want a profile image, use a Gravatar email'
/>
<TextFieldGroup
type='password'
className={errors.password}
placeholder="* Password"
name="password"
value={this.state.password}
onChange={this.onChange}
error={errors.password}
/>
<TextFieldGroup
type='password'
className={errors.password2}
placeholder="* Confirm Password"
name="password2"
value={this.state.password2}
onChange={this.onChange}
error={errors.password2}
/>
<input type='submit' className='btn btn-info btn-block mt-4' />
</form>
</div>
</div>
</div>
</div>
);
}
}
RegisterScreen.propTypes = {
registerUser: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors
});
const mapDispatchToProps = dispatch => ({
registerUser: bindActionCreators(registerUser, dispatch)
});
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(RegisterScreen));
You should define the PropTypes in the component as you have in the example there. When deciding when to use PropTypes for static typing, you should always guard against incoming props that can directly affect the desired result of the component when rendered. By that I mean, if the component requires "auth" or "errors" props, then you should define the PropTypes for the component receiving those properties, whether through HoC in this case redux or any other mode of passing data down.

Submitting form returns proxy object instead of form data in Reactjs

I am creating a login form using semantic-ui in Reactjs. Please find the code below:
The the login form itself:
import React from 'react';
import { Form, Button } from 'semantic-ui-react';
const LoginPage = ({ email, password, handleChange, handleSubmit, errors }) => (
<Form onSubmit={handleSubmit}>
<Form.Field>
<label htmlFor="email">Email:</label>
<input
type="email"
name="email"
id="email"
placeholder="example#example.com"
value={email}
onChange={(e) => handleChange(e)}
/>
</Form.Field>
<Form.Field>
<label htmlFor="password">Password:</label>
<input
type="password"
name="password"
id="password"
value={password}
onChange={(e) => handleChange(e)}
/>
</Form.Field>
<Button primary> Login </Button>
</Form>
);
export default LoginPage;
The login container (parent component) is as below:
import React, { Component } from 'react';
import { LoginPage } from '../components';
import Validator from 'validator';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
data: {
email: '',
password: ''
},
loading: false,
errors: {}
}
}
handleChange = (e) => {
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
});
}
handleSubmit = (values) => {
console.log(values);
const errors = this.validate(this.state.data);
this.setState({
errors: errors
})
}
validate = (data) => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Invalid Email";
if (!data.password) errors.password = "Password cannot be blank";
return errors;
}
render() {
return (
<LoginPage
email={this.state.data.email}
password={this.state.data.password}
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
errors={this.state.errors}
/>
)
}
}
export default Login;
When I try to console log values in the handleSubmit function of the parent component it always returns proxy object instead of form values or form data.
Proxy {dispatchConfig: {…}, _targetInst: ReactDOMComponent, isDefaultPrevented: ƒ, isPropagationStopped: ƒ, _dispatchListeners: ƒ, …}
Could anyone let me know where am I going wrong ?
Thanks
The "Proxy" object seems to be an Event object. Indeed the semantic-ui docs say
Our handles data just like a vanilla React . See React's controlled components docs for more.
and here is the vanilla react example it refers to:
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
So with this library it is your own duty to retrieve the form data from your state/store, it is not passed to onSubmit automatically.
handleSubmit = (e) => {
console.log(e);
const errors = this.validate(this.state.data);
this.setState({
errors: errors
})
}
So actually it is correct as you have it, because you are not using this parameter e/values anywhere. You were only confused by the log and your variable name. You could simply omit it.

Resources