I'm building a simple signup form in react native but it seems some states are not working properly. I know about the fact that states update asynchronously but still, I don't understand what is happening here
Signup component
import React, {useEffect, useState} from "react";import { StyleSheet, View, Pressable, ScrollView} from "react-native";import {AntDesign} from '@expo/vector-icons'import Text from '../components/Text'import Input from "../components/Input";import Button from "../components/Button";import Nope from "../utils/validator";import type { InputState } from "../components/Input";interface Props {}const initialInputState: InputState = { errorMsg: '', isValidated: false, value: ''}const SignUp:React.FC<Props> = () => { const [email, setEmail] = useState(initialInputState) const [password, setPassword] = useState(initialInputState) const [confirmPassword, setConfirmPassword] = useState(initialInputState) const [isValidationTriggered, setIsValidationTriggered] = useState(false) const [isValidated, setIsValidated] = useState(false) function triggerValidation(){ setIsValidationTriggered(true) } const handleSubmit = () => { console.log({isValidated, isValidationTriggered}) if(!isValidated){ console.log('Not validated') !isValidationTriggered && triggerValidation() return } const formData = { email: email?.value, password: password?.value, confirmPassword: confirmPassword?.value } console.log({formData}) } useEffect(() => { setIsValidated( (email?.isValidated && password?.isValidated && confirmPassword?.isValidated) ?? false ) }, [email, password, confirmPassword]) useEffect(() => { console.log(isValidated) }, [isValidated]) return (<ScrollView keyboardShouldPersistTaps="handled"><View style={styles.container}><View style={styles.header}><Text h1 bold>Sign up</Text></View><View style={styles.form}><Input placeholder="Email or phone number" validator={Nope.isEmail().isRequired().validate()} triggerValidation = {isValidationTriggered} onChangeState={state => setEmail(state)} /><Input secure placeholder="Password" validator={Nope.isMin(4).isRequired().validate()} triggerValidation = {isValidationTriggered} onChangeState={state => setPassword(state)} /><Input secure placeholder="Confirm password" validator={Nope.isEqual(password?.value ?? '', 'Passwords should match').validate()} triggerValidation = {isValidationTriggered} onChangeState={state => setConfirmPassword(state)} /><Button fullWidth style={styles.topSpace} disabled={isValidationTriggered? !isValidated : false} onPress={() => handleSubmit()}><Text bold color="#fff">Sign up</Text></Button><Button secondary fullWidth style={styles.topSpace}><AntDesign name="google" size={24} color="#fff" style={{marginRight: 10}} /><Text bold color="#fff">Sign in with google</Text></Button></View><View style={styles.footer}><Text>Already have an account, </Text><Pressable><Text bold color="#1263f8">Sign in</Text></Pressable></View></View></ScrollView> )}
Input component
import React, {useEffect, useRef, useState} from "react";import { StyleSheet, TextInput, View, ViewStyle} from "react-native";import type {StyleProp, KeyboardTypeOptions} from 'react-native'import Text from './Text'import IconButton from "./IconButton";import { Ionicons } from '@expo/vector-icons'interface Props { placeholder?: string, secure?: boolean keyboardType?: KeyboardTypeOptions style?: StyleProp<ViewStyle> inputStyle?: {} solid?:boolean outlined?:boolean bind?: [string, React.Dispatch<React.SetStateAction<string>>] validator?: (text: string) => string triggerValidation?:boolean onChangeState?: (state: InputState) => void}export interface InputState { value: string errorMsg: string isValidated: boolean}const Input:React.FC<Props> = ({ placeholder, keyboardType, secure, style, inputStyle, solid, outlined, bind, validator, triggerValidation, onChangeState}) => { let inputRef = useRef<TextInput | null>(null) const [value, setValue] = bind ? bind : useState('') const [errorMsg, setErrorMsg] = useState('') const [startValidation, setStartValidation] = useState(false) const [showSecureText, setShowSecureText] = useState(false) function changeTextHandler(text: string){ setValue(text) } function blurHandler(){ if(startValidation === false){ setStartValidation(true) } } useEffect(() => { if(startValidation && validator !== undefined){ setErrorMsg(validator(value)) } }, [value, startValidation, validator]) useEffect(() => { if(triggerValidation && !startValidation){ setStartValidation(true) } }, [triggerValidation, startValidation]) useEffect(() => { if(onChangeState !== undefined){ onChangeState({ value, errorMsg, isValidated: /^\s*$/.test(errorMsg) && startValidation }) } }, [value, errorMsg, startValidation]) return (<View style={[styles.inputWrapper, style]}><TextInput placeholder={placeholder} keyboardType={keyboardType} secureTextEntry={secure && !showSecureText} style={[ styles.input, inputStyle, (outlined || (!outlined && !solid))&& styles.outlined, solid && styles.solid, !/^\s*$/.test(errorMsg) && styles.error ]} value={value} onChangeText={changeTextHandler} onBlur={blurHandler} ref={ref => inputRef.current = ref} /> { secure&& (<IconButton style={styles.toggleBtn} onPress={() => { setShowSecureText(v => !v) inputRef.current?.focus() }}> { showSecureText ? <Ionicons name="eye-off" size={24} color="#666" /> : <Ionicons name="eye" size={24} color="#666" /> }</IconButton> ) } { !/^\s*$/.test(errorMsg)&& <Text color="#f00" sm style={styles.errorMsg}>{errorMsg}</Text> }</View> )}
When I submit the form after making sure the isValidated = true
it still runs the !isValidated
branch