Reputation: 168
This seems like a simple thing to do but after much fiddling, I can't figure out what's wrong. I'm a noob to React so forgive me.
I have a form for logging in. Like most login forms, it's asking for a username and password. Then it has a button to submit. My understanding is that a component will re-render if the state is changed. I have onchange
events on each input field that updates the state. So if the field is empty, I press the button to submit, I would expect that the error will show. If I fill in a field, I would expect the error message to go away because the state changed. Am I misunderstanding?
Here is my event handler:
handleLogin(event) {
event.preventDefault();
if (this.state.username == '') {
this.setState({usernameError: "Need to enter a username"})
return;
}
if (this.state.password == '') {
this.setState({passwordError: "Need to enter a password"})
return;
}
}
And the form:
render() {
return(
<form className="login-form">
<h1 className="login-form__header"><FontAwesomeIcon icon="key" className="registration-form__icon"/><i className="fal fa-route-highway"></i>Log Into Your Account</h1>
<input type="text" name="username" placeholder="Username" className="login-form__input" onChange={(event,newValue) => this.setState({username:newValue})}/>
{this.state.usernameError &&
<p class="login-form__error"><FontAwesomeIcon icon="times-circle"/> {this.state.usernameError}</p>
}
<input type="password" name="password" placeholder="Password" className="login-form__input" onChange={(event,newValue) => this.setState({password:newValue})}/>
{this.state.passwordError &&
<p class="login-form__error"><FontAwesomeIcon icon="times-circle"/> {this.state.passwordError}</p>
}
<button className="login-form__button" onClick={this.handleLogin}>Log Into Your Account</button>
</form>
);
}
Upvotes: 0
Views: 1587
Reputation: 15688
Right, but you never configured any logic to clear the errors if the field is not empty. Currently, there isnt any logic set-up to turn usernameError
and passwordError
back to an empty-string or null value.
You might be under the impression that the state
is cleared when you re-render but that is not the case. The state-object
prior to the re-render still persists, only changing the key-value pair(s) you last updated within this.setState()
.
Try this:
handleLogin(event) {
event.preventDefault();
const { username, password } = this.state
this.setState({
...this.state,
usernameError: username.length > 0 ? "" : "Need to enter a username",
passwordError: password.length > 0 ? "" : "Need to enter a password"
})
}
Here's a working sandbox with a sligtly modified version of your code. (I removed the FontAwesomeIcons). https://codesandbox.io/s/cool-meninsky-y9r4y
Upvotes: 2
Reputation: 430
As mentioned by @Satyaki onChange={(event,newValue) => this.setState({username:newValue})}
is not a good option you should define separate method for this, alternatively you can change your code to as follows:
onChange={(event,newValue) => this.setState({username:newValue})}, () => {})
This will make sure to complete the lifecycle of setState.
Upvotes: 0
Reputation: 5604
Hi you can try the below code
function validate(email, username, password) {
// true means invalid, so our conditions got reversed
return {
username: username.length === 0, //true if username is empty
password: password.length === 0, //true if password is empty
};
}
class LoginForm extends React.Component {
constructor() {
super();
this.state = {
username: '',
password: '',
touched: {
username: false,
password: false,
},
};
}
handleUsernameChange = (evt) => {
this.setState({ username: evt.target.value });
}
handlePasswordChange = (evt) => {
this.setState({ password: evt.target.value });
}
handleBlur = (field) => (evt) => {
this.setState({
touched: { ...this.state.touched, [field]: true },
});
}
handleSubmit = (evt) => {
if (!this.canBeSubmitted()) {
evt.preventDefault();
return;
}
const { username, password } = this.state;
alert(`Logined: ${email} password: ${password}`);
}
canBeSubmitted() {
const errors = validate(this.state.username, this.state.password);
const isDisabled = Object.keys(errors).some(x => errors[x]);
return !isDisabled;
}
render() {
const errors = validate(this.state.username, this.state.password);
const isDisabled = Object.keys(errors).some(x => errors[x]);
const shouldMarkError = (field) => {
const hasError = errors[field];
const shouldShow = this.state.touched[field];
return hasError ? shouldShow : false;
};
return (
<form className="login-form" onSubmit={this.handleSubmit}>
<h1 className="login-form__header">
<FontAwesomeIcon icon="key" className="registration-form__icon"/>
<i className="fal fa-route-highway"></i>Log Into Your Account
</h1>
<input
className={shouldMarkError('username') ? "error" : ""}
type="text" name="username" placeholder="Username"
value={this.state.username}
onBlur={this.handleBlur('username')
onChange={this.handleUsernameChange} />
<p className={shouldMarkError('username') ? "error" : "hidden"}>
<FontAwesomeIcon icon="times-circle"/> Need to enter a username
</p>
<input type="password" name="password" placeholder="Password"
className={shouldMarkError('password') ? "error" : ""}
value={this.state.password}
onChange={this.handlePasswordChange}
onBlur={this.handleBlur('password')} />
<p className={shouldMarkError('password') ? "error" : "hidden"}>
<FontAwesomeIcon icon="times-circle"/> Need to enter a password
</p>
<button disabled={isDisabled} className="login-form__button"
onClick={this.handleLogin}>Log Into Your Account</button>
</form>
)
}
}
Hope the code could helpful for you. You can also refer the Demo Validation for Signup
Upvotes: 0
Reputation: 751
First of all, onChange={(event,newValue) => this.setState({username:newValue})}
this is not a good approach, as it will create a new function on every render. So I would suggest to create a dedicated function like -
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
// Make sure the name is as per with your html username password and update the state accordingly
this.setState({
[name]: value
});
}
Do remember to reset the usernameError
and passwordError
properties of your state on each related onChange
event. Otherwise the error message will persist on HTML.
Upvotes: 0