如何解决React native不会使用所有新状态重新渲染
我正在建立注册表,但遇到了问题。用户填写完字段后,我用正则表达式进行验证检查。每个验证功能都会设置一条错误消息。即使我故意触发了所有这些错误,但如果我提交表单,则只会出现一个错误。这是我的代码:
function RegisterScreen(): JSX.Element{
const pwInput = React.createRef();
const [firstName,setFirstName] = useState('');
const [lastName,setLastName] = useState('');
const [email,setEmail] = useState('');
const [password,setPassword] = useState('');
const [confirmPassword,setConfirmPassword] = useState('');
const [birthday,setBirthday] = useState<Date | null>(null);
const [isSelected,setSelection] = useState(false);
const [openTerms,setOpenTerms] = useState(false);
const [emailError,setEmailError] = useState<string | null>(null);
const [passError,setPassError] = useState<string | null>(null);
const [confPassError,setConfPassError] = useState<string | null>(null);
const [isTermsChecked,setIsTermsChecked] = useState<string | null>(null);
function _validateEmail(): boolean{
const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if(re.test(email))
return true;
else{
setEmailError(RegisterErrors.emailError);
return false;
}
}
function _validatePw(): boolean{
const re = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/
if(re.test(password)) return true;
else{
setPassError(RegisterErrors.pwWeak);
return false
}
}
function _pwMatch(): boolean{
if(password == confirmPassword){
return true;
}else{
setConfPassError(RegisterErrors.pwConfirmMatchError);
return false;
}
}
function _validateAge(): boolean{
return true;
}
function _validateTermsAndCond(): boolean{
return true;
}
function validateFieldsAndRegister(){
console.log(email);
console.log(password);
console.log(confirmPassword);
if( _validateEmail() && _validatePw() && _validateAge() && _validateTermsAndCond() && _pwMatch()){
//trimite la firebase
console.log("okay")
}else{
console.log('wrong fields')
}
}
return(
<SafeAreaView style={{flex:1}}>
<ScrollView>
<View style = {{flex:1,alignItems: "center",justifyContent:"center",backgroundColor:"white"}}>
<TermsAndConditions open = {openTerms} close = { ()=>setOpenTerms(false) }/>
<Image source={require("../../images/logoR.png")} style={styles.logoImg}/>
<Text style={styles.mainText}>Register</Text>
<Input
containerStyle={styles.inputView}
inputContainerStyle={{backgroundColor:"white"}}
placeholder="First Name..."
placeholderTextColor="rgb(0,0)"
errorStyle={{ color: 'red' }}
onChangeText={text => setFirstName(text)}/>
<Input
containerStyle={styles.inputView}
placeholder="Last Name..."
placeholderTextColor="rgb(0,0)"
errorStyle={{ color: 'red' }}
onChangeText={text => setLastName(text)}/>
<Input
onFocus={()=>{setPassError(null)}}
secureTextEntry
containerStyle={styles.inputView}
placeholder="Password..."
placeholderTextColor="rgb(0,0)"
errorStyle={{ color: 'red' }}
errorMessage={passError}
onChangeText={text =>setPassword(text)}/>
<Input
secureTextEntry
onFocus = {()=>{setConfPassError(null)}}
containerStyle={styles.inputView}
placeholder="Confirm Password..."
placeholderTextColor="rgb(0,0)"
errorStyle={{ color: 'red' }}
errorMessage={confPassError}
onChangeText={text =>setConfirmPassword(text)}/>
<Input
containerStyle={styles.inputView}
onFocus={()=>{setEmailError(null)}}
placeholder="Email..."
placeholderTextColor="rgb(0,0)"
errorStyle={{ color: 'red' }}
errorMessage={emailError}
onChangeText={text => setEmail(text)}/>
<View style={styles.checkboxContainer}>
<CheckBox
value={isSelected}
onValueChange={()=>{setSelection(!isSelected)}}
style={styles.checkbox}
/>
<TouchableOpacity onPress = {()=> {setOpenTerms(true);}}>
<Text style={styles.label}>Terms and Conditions</Text>
</TouchableOpacity>
</View>
<TouchableOpacity style={{...styles.inputView,...styles.regBtnContainer}} onPress = {()=>{validateFieldsAndRegister()}}>
<Text style = {styles.txtRegBtn}>Register</Text>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
)
}
如果我在validateFieldsAndRegister的if语句之前调用验证功能,它将起作用。错误将显示在3个字段中。
这是我显示的错误
export const RegisterErrors = {
emailError: "You must enter a valid email",pwConfirmMatchError:"The passwords you entered are not the same",termsAndCondError:"You must read and agree with the Terms and Conditions",birthdayError:"You must be 21 or older",pwWeak:"Your password must contain: a lowercase letter,a acapital letter,a number and minimum 8 characters"
}
解决方法
以下是说明正在发生的事情的摘要。它说明了三种更新状态的策略。
第一个将所有三个setState()
调用分组为一个函数调用,并且不使用if()
语句检查结果。状态更改会立即显示。
第二个命令将更新分为三个分别调用async
函数的调用,这些函数依次调用await
一个超时函数,然后再调用setState()
。这些调用是在OP从if()
语句中进行时进行的。每个异步函数都返回一个Promise,该Promise被评估为“真”,并且我们看到“ promise”已记录到控制台。超时结果然后滴入。
第三种情况最接近OP的问题。它还从if()
语句中进行单独的调用,但它们是同步的并返回false
。第一个调用完成了它的setState()
调用,返回false并从if内部停止进一步的调用。由于状态已更改,React调用了渲染,因此我们看到了单个状态更改。
所有这一切的结果是,最好是在if()
语句之前进行验证调用,或者更好的是,收集所有验证结果,然后将所有setState()
调用分组为一个。单一功能。这将使React可以更有效地对这些更改进行分组,并调用尽可能少的渲染器。
(抱歉,代码段混乱,内置的babel似乎无法处理async/await
)
.container {
display: flex;
}
.example {
margin: 1rem;
padding: 1rem;
border: 1px solid gray;
}
button {
margin: 1rem;
}
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
const { useState } = React
function App() {
const [stateOne,setStateOne] = useState(1);
const [stateTwo,setStateTwo] = useState(1);
const [stateThree,setStateThree] = useState(1);
const cycleStateSingle = () => {
setStateOne((state) => state + 1);
setStateTwo((state) => state + 1);
setStateThree((state) => state + 1);
}
const [stateOnePromise,setStateOnePromise] = useState(1);
const [stateTwoPromise,setStateTwoPromise] = useState(1);
const [stateThreePromise,setStateThreePromise] = useState(1);
const cycleOne = async () => {
await new Promise(resolve => setTimeout(resolve,1000));
setStateOnePromise((state) => state + 1);
}
const cycleTwo = async () =>{
await new Promise(resolve => setTimeout(resolve,2000));
setStateTwoPromise((state) => state + 1);
}
const cycleThree = async () =>{
await new Promise(resolve => setTimeout(resolve,3000));
setStateThreePromise((state) => state + 1);
}
const cycleStatePromise = () => {
if (cycleOne(true) && cycleTwo(true) && cycleThree(true)) {
console.log('promise');
}
}
const [stateOneStepped,setStateOneStepped] = useState(1);
const [stateTwoStepped,setStateTwoStepped] = useState(1);
const [stateThreeStepped,setStateThreeStepped] = useState(1);
const cycleOneStepped = () => {
setStateOneStepped((state) => state + 1);
return false;
}
const cycleTwoStepped = () =>{
setStateTwoStepped((state) => state + 1);
return false;
}
const cycleThreeStepped = () =>{
setStateThreeStepped((state) => state + 1);
return false;
}
const cycleStateStepped = () => {
if (cycleOneStepped() && cycleTwoStepped() && cycleThreeStepped()) {
console.log('stepped');
}
}
return (
<div className="container">
<div className="example">
<div className="state-1">State 1: {stateOne}</div>
<div className="state-2">State 2: {stateTwo}</div>
<div className="state-3">State 3: {stateThree}</div>
<button type="button" onClick={cycleStateSingle}>Single State Change</button>
</div>
<div className="example">
<div className="state-1">State 1: {stateOnePromise}</div>
<div className="state-2">State 2: {stateTwoPromise}</div>
<div className="state-3">State 3: {stateThreePromise}</div>
<button type="button" onClick={cycleStatePromise}>Promise State Change</button>
</div>
<div className="example">
<div className="state-1">State 1: {stateOneStepped}</div>
<div className="state-2">State 2: {stateTwoStepped}</div>
<div className="state-3">State 3: {stateThreeStepped}</div>
<button type="button" onClick={cycleStateStepped}>Stepped State Change</button>
</div>
</div>
);
}
ReactDOM.render(<App />,document.getElementById('root'));
</script>
<div id="root"></div>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。