我正尝试如下验证password
和confirmPassword
字段的值。
问题是状态更新似乎滞后于一个事件(字符)。
例如:如果password.value =“ pass1234”,则尽管输入了“ 4”,但确认时的ConfirmPassword.value为“ pass123”。因此,验证发生在状态更新之前。
解决此问题的最佳方法是什么?
import React, { Component } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import Aux from "../../hoc/Aux/Aux";
import Button from "../../components/UI/Button/Button";
import Input from "../../components/UI/Input/Input";
import Spinner from "../../components/UI/Spinner/Spinner";
import classes from "./Auth.module.css";
import * as actions from "../../store/actions/index";
class Auth extends Component {
state = {
controls: {
name: {
elementType: "input",
elementConfig: {
placeholder: "name"
},
value: "",
validation: {
required: true,
minLength: 4
},
valid: false,
touched: false
},
email: {
elementType: "input",
elementConfig: {
type: "email",
placeholder: "Email ID"
},
value: "",
validation: {
required: true,
isEmail: true
},
valid: false,
touched: false
},
password: {
elementType: "input",
elementConfig: {
type: "password",
placeholder: "password"
},
value: "",
validation: {
required: true,
minLength: 8
},
valid: false,
touched: false
},
confirmPassword: {
elementType: "input",
elementConfig: {
type: "password",
placeholder: "confirm password"
},
value: "",
validation: {
required: true,
minLength: 8,
passwordMatch: true
},
valid: false,
touched: false
}
},
isSignup: false
};
checkValidity(value, rules) {
let isValid = true;
if (!rules) {
return true;
}
if (rules.required) {
isValid = value.trim() !== "" && isValid;
}
if (rules.minLength) {
isValid = value.length >= rules.minLength && isValid;
}
if (rules.maxLength) {
isValid = value.length <= rules.maxLength && isValid;
}
if (rules.isEmail) {
const pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
isValid = pattern.test(value) && isValid;
}
if (rules.isNumeric) {
const pattern = /^\d+$/;
isValid = pattern.test(value) && isValid;
}
if (rules.passwordMatch) {
const pwd = this.state.controls.password.value;
console.log("pwd: " + pwd);
console.log("pwdConfirm: " + this.state.controls.confirmPassword.value);
isValid = this.state.controls.confirmPassword.value === pwd;
}
return isValid;
}
inputChangedHandler = (event, controlName) => {
let updatedControls = {
...this.state.controls,
[controlName]: {
...this.state.controls[controlName],
value: event.target.value,
valid: this.checkValidity(
event.target.value,
this.state.controls[controlName].validation
),
touched: true
}
};
this.setState({ controls: updatedControls });
};
submitHandler = event => {
event.preventDefault();
if (!this.state.isSignup) {
this.props.onAuth(
this.state.controls.email.value,
this.state.controls.password.value,
this.state.isSignup
);
} else {
this.props.onSignUp(
this.state.controls.name.value,
this.state.controls.email.value,
this.state.controls.password.value,
this.state.controls.confirmPassword.value
);
}
};
switchAuthModeHandler = () => {
this.setState(prevState => {
return { isSignup: !prevState.isSignup };
});
};
render() {
const formElementsArray = [];
if (!this.state.isSignup) {
for (let key in this.state.controls) {
if (key !== "name" && key !== "confirmPassword") {
formElementsArray.push({
id: key,
config: this.state.controls[key]
});
}
}
} else {
for (let key in this.state.controls) {
formElementsArray.push({
id: key,
config: this.state.controls[key]
});
}
}
let form = null;
form = formElementsArray.map(formElement => (
<Input
key={formElement.id}
elementType={formElement.config.elementType}
elementConfig={formElement.config.elementConfig}
value={formElement.config.value}
invalid={!formElement.config.valid}
shouldValidate={formElement.config.validation}
touched={formElement.config.touched}
changed={event => this.inputChangedHandler(event, formElement.id)}
/>
));
let button;
if (!this.state.isSignup) {
button = <button btnType="Success">LOGIN</button>;
} else {
button = <button btnType="Success">REGISTER</button>;
}
let buttonRegister = null;
if (!this.state.isSignup) {
buttonRegister = (
<button btnType="SignUp" onClick={this.switchAuthModeHandler}>
SIGN UP FREE!
</button>
);
} else {
buttonRegister = (
<button btnType="SignUp" onClick={this.switchAuthModeHandler}>
Back to Login!
</button>
);
}
if (this.props.loading) {
form = <Spinner />;
}
let errorMessage = null;
if (this.props.error && !this.state.isSignup) {
errorMessage = <p>Email or Password is incorrect</p>;
}
if (this.props.error && this.state.isSignup) {
errorMessage = <p>Please confirm email is valid and passwords match</p>;
}
if (this.props.error && this.state.isSignup) {
let errorObj = JSON.parse(`${this.props.error}`);
if (errorObj.code == "11000") {
errorMessage = (
<p>
Email is already in use. Please reset your password, if you don't
remember it
</p>
);
}
}
let authRedirect = null;
if (this.props.isAuthenticated) {
authRedirect = <Redirect to={this.props.authRedirectPath} />;
}
return (
<div className={classes.Auth}>
{authRedirect}
{errorMessage}
<form onSubmit={this.submitHandler}>
{form}
{button}
</form>
{buttonRegister}
</div>
);
}
}
const mapStateToProps = state => {
return {
loading: state.auth.loading,
error: state.auth.error,
isAuthenticated: state.auth.token !== null,
role: state.auth.role,
userName: state.auth.name,
userPoints: state.auth.userPoints,
userJourneyPoints: state.auth.userJourneyPoints,
journeysCompleted: state.auth.journeysCompleted,
userLevel: state.auth.userLevel,
useHints: state.auth.useHints
};
};
const mapDispatchToProps = dispatch => {
return {
onAuth: (email, password, isSignup) =>
dispatch(actions.auth(email, password, isSignup)),
onSignUp: (name, email, password, confirmPassword) =>
dispatch(actions.signUp(name, email, password, confirmPassword))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Auth);
答案 0 :(得分:0)
浏览代码后,似乎可以通过将target.event.value
更改为“确认”来调用password
时将inputChangedHandler
与confirmPassword
的当前状态进行比较来解决该问题。密码”输入。您当前正在做的是在password
有机会更新之前比较confirmPassword
和target.event.value
状态。但是,“确认密码”输入中的inputChangedHandler
在调用componentDidUpdate
时将具有更新的值。
另一种解决方案是在inputChangedHandler
内验证表单,而不是在调用componentDidUpdate
时立即进行验证。通过在$(document).on("keyup", "[id^='numberunits']", function() {
var total=$("[id^='linetotal']");
var row = $( this ).attr('id').split('_').slice(1);
var qty=$("#numberunits_"+ row );
var price=$("#priceperunit_" + row );
var total=isNaN(parseInt(qty.val()* $("#priceperunit_"+row).val())) ? 0 :(qty.val()* $("#priceperunit_"+row).val())
var roundedTotal = parseFloat(Math.round(total * 100) / 100).toFixed(2);
$("#linetotal_"+row).val(roundedTotal);
if($("#numberunits_"+ row ).val() !== "" && $("#priceperunit_" + row).val() !== ""){
$('#btnAdd_1').removeAttr('disabled');
}
var totalVal = 0;
$("[id^='linetotal']").each(function(){
totalVal += parseFloat($(this).val()) ;
});
roundedTotalVal = parseFloat(Math.round(totalVal * 100) / 100).toFixed(2);
$("#grandtotal").val(roundedTotalVal);
});
$(document).on("keyup", "[id^='priceperunit']", function() {
var total=$("[id^='linetotal']");
var row = $( this ).attr('id').split('_').slice(1);
var qty=$("#numberunits_"+ row );
var price=$("#priceperunit_" + row );
var total=isNaN(parseInt(qty.val()* $("#priceperunit_"+row).val())) ? 0 :(qty.val()* $("#priceperunit_"+row).val())
var roundedTotal = parseFloat(Math.round(total * 100) / 100).toFixed(2);
$("#linetotal_"+row).val(roundedTotal);
if($("#numberunits_"+ row ).val() !== "" && $("#priceperunit_" + row).val() !== ""){
$('#btnAdd_1').removeAttr('disabled');
}
var totalVal = 0;
$("[id^='linetotal']").each(function(){
totalVal += parseFloat($(this).val()) ;
});
roundedTotalVal = parseFloat(Math.round(totalVal * 100) / 100).toFixed(2);
$("#grandtotal").val(roundedTotalVal);
});
// Cloned Section 1 Script
$('#btnAdd_1').click(function () {
var num = $('.clonedInput_1').length, // Checks to see how many "duplicatable" input fields we currently have
newNum = new Number(num + 1), // The numeric ID of the new input field being added, increasing by 1 each time
phpNum = new Number(newNum - 1), // The numeric ID of the new input field being added, increasing by 1 each time
newElem = $('#entry' + num).clone().attr('id', 'entry' + newNum).fadeIn('slow'); // create the new element via clone(), and manipulate it's ID using newNum value
/* This is where we manipulate the name/id values of the input inside the new, cloned element
Below are examples of what forms elements you can clone, but not the only ones.
There are 2 basic structures below: one for an H2, and one for form elements.
To make more, you can copy the one for form elements and simply update the classes for its label and input.
Keep in mind that the .val() method is what clears the element when it gets cloned. Radio and checkboxes need .val([]) instead of .val('').
*/
// numberunits - text
newElem.find('.label_numberunits').attr('for', 'numberunits_'+ newNum);
newElem.find('.input_numberunits').attr('id', 'numberunits_'+ newNum).attr('name', 'purchline[' + phpNum + '][numberunits]').val('');
// priceperunit - text
newElem.find('.label_priceperunit').attr('for', 'priceperunit_'+ newNum);
newElem.find('.input_priceperunit').attr('id', 'priceperunit_'+ newNum).attr('name', 'purchline[' + phpNum + '][priceperunit]').val('');
// linetotal - text
newElem.find('.label_linetotal').attr('for', 'linetotal_'+ newNum);
newElem.find('.input_linetotal').attr('id', 'linetotal_'+ newNum).attr('name', 'purchline[' + phpNum + '][linetotal]').val('');
// Insert the new element after the last "duplicatable" input field and set focus on first field
$('#entry' + num).after(newElem);
$('numberunits_'+ newNum).focus();
// Enable the "remove" button. This only shows once you have a duplicated section.
$('#btnDel_1').attr('disabled', false);
$('#btnAdd_1').attr('disabled', true);
$("#add_purchase_lines").parsley().destroy();
$('.filled').remove()
$('#add_purchase_lines').parsley();
});
$('#btnDel_1').click(function () {
// Confirmation dialog box. Works on all desktop browsers and iPhone.
if (confirm("Are you sure you wish to remove this section? This cannot be undone."))
{
var num = $('.clonedInput_1').length;
// how many "duplicatable" input fields we currently have
$('#entry' + num).slideUp('slow', function () {$(this).remove();
// if only one element remains, disable the "remove" button
if (num -1 === 1)
$('#btnDel_1').attr('disabled', true);
// enable the "add" button
$('#btnAdd_1').attr('disabled', true).prop('value', "add section");});
var totalVal = 0;
$("[id^='linetotal']").each(function(){
totalVal += parseFloat($(this).val()) ;
});
totalVal = totalVal - parseFloat($("#linetotal_"+num).val());
roundedTotalVal = parseFloat(Math.round(totalVal * 100) / 100).toFixed(2);
$("#grandtotal").val(roundedTotalVal);
}
return false; // Removes the last section you added
});
// Enable the "add" button
$('#btnAdd_1').attr('disabled', true);
// Disable the "remove" button
$('#btnDel_1').attr('disabled', true);
内部进行验证,可以确保状态有时间更新。