Home > database >  How can I deal with the state updating asynchronously?
How can I deal with the state updating asynchronously?

Time:01-12

I have a login page where if a user enters the wrong credentials or submits blank fields, an error will be displayed on the page. Currently, when a user fails to signin with the right credentials, the error will only be displayed on the second click. I'm aware that my current problem is due to the state updating asynchronously, but I'm not sure how to resolve the problem in my code:

onst Login: React.FC<Props> = () => {
    const user = useAppSelector(selectUser);
    const auth = useAppSelector(selectAuth);
    const dispatch = useAppDispatch();
    ...
    const [signInError, setSignInError] = useState<boolean>(false);

    const handleSignInError = () => {
        if (auth.error?.status === 401 && auth.error.message === Constants.Errors.WRONG_CREDENTIALS) {
            setSignInError(true);
        }
    }

    const renderSigninError = () => {
        if (signInError) {
            return (
                <Box paddingTop={2.5}>
                <Alert variant="outlined" severity="error">
                    {Constants.Auth.FAILED_SIGN_IN}
                </Alert>
            </Box>
            );
        } else {
            return (
                <div/>
            );
        }
    }

    const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        const formData: any = new FormData(event.currentTarget);
        const loginData: LoginData = {
            email: formData.get("email"),
            password: formData.get("password"),
        }
        try {
            const res: any = await dispatch(login(loginData));
            const resType: string = res.type;
            if (resType === "auth/login/fulfilled") {
                const userPayload: UserLogin = res.payload;
                const loginUser: UserInterface = {
                    ...
                }
                setSignInError(false);
                dispatch(setUser(loginUser))
                navigate("/");
            }
            else {
                console.log("Failed to login");
                handleSignInError();
            }

        }
        catch (error: any) {
            console.log(error.message);
        }
    }

    return (
        <Box
            ...code omitted...

            {renderSigninError()}

            ...
    )
}

What can I do to make sure that when the app loads and the user fails to login on the first click, the state for signInError should be true and the error displays?

CodePudding user response:

You have at least 2 options.

  1. add a conditional component.

  2. Add a useEffect listenning for signInError and handle there as you want. It will trigger everytime signInError state changes

     import React from 'react';
       const [signInError, setError] = useState(false)
    
      import React from 'react';
     const [signInError, setError] = useState(false)
    
     useEffect(() => {
       console.log('new signInError value >', signInError)
     // do whatever you want
     }, [signInError])
    
    
     export function App(props) {
         return (
             <div className='App'>
               {
                 signInError ? (<p>something happened</p>) : null
               }
             </div>
         );
     }
    

There might be better approaches. Hope this can help you

CodePudding user response:

I found a work around by changing handleSignInError() to update the state directly through setSignInError(true) as in:

const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        const formData: any = new FormData(event.currentTarget);
        const loginData: LoginData = {
            email: formData.get("email"),
            password: formData.get("password"),
        }
        try {
            const res: any = await dispatch(login(loginData));
            const resType: string = res.type;
            if (resType === "auth/login/fulfilled") {
                const userPayload: UserLogin = res.payload;
                const loginUser: UserInterface = {
                    ...
                }
                setSignInError(false);
                dispatch(setUser(loginUser))
                navigate("/");
            }
            else {
                console.log("Failed to login");
                setSignInError(true); //changed here
            }

        }
        catch (error: any) {
            console.log(error.message);
        }
    }

Could someone help me understand why using another function initially didnt work?

  • Related