状态未在反应钩子中更新

时间:2021-01-12 12:35:43

标签: reactjs react-hooks

我创建了一个登录表单,用户需要在其中输入他的电子邮件 ID 和 OTP。下面是我的代码 -

import { useState } from 'react';
import axios from '../api/axios';

const useLogin = () => {
    const [user, setUser] = useState(false);

    const auth = async (value, OTP) => {

        let config = {
            method: 'POST',
            url: '/api/user/generateToken',
            headers: {
                Authorization: 'value'
            },
            data: {
                username: value,
                password: OTP
            }
        };

        try {
            const response = await axios(config);
            if (response.data.Status === "Failure") {
                throw response.data.Message;
            } else {
                setUser(true);
                return { status: response.data.Status, isAuth: user }
            }
        } catch (err) {
            setUser(false);
            return { status: undefined, message: err, isAuth: user };
        }

    }

    return { auth, user };


}

export default useLogin

这里一切正常,唯一的问题是当我在我的组件中调用这个函数时,我会收到 isAuth 总是假的。下面是我的组件代码 -

import React, { Fragment, useRef, useEffect, useState } from 'react';
import { useLocation, useHistory } from "react-router-dom";
import { css } from "@emotion/core";
import ScaleLoader from "react-spinners/ScaleLoader";
import '../css/login.css';
import '../css/common.css';
import logo from '../assets/engageLogo.png';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import useLogin from './../hooks/useOTP';

const override = css`
  display: block;
  margin: 0 auto;
  border-color: #fff;
`;

const OTP = () => {
    const [loading, setLoading] = useState(false);
    const [color] = useState("#ffffff");
    const [APIResponse, setAPIResponse] = useState(false);
    const [APIMessage, setAPIMessage] = useState('')
    const login = useLogin();

    const location = useLocation();
    const history = useHistory();

    const inputRef = useRef();
    const readRef = useRef();
    const buttonRef = useRef();

    const schema = Yup.object({
        otp: Yup.string().required("OTP is Required")
    });

    const handleChangeError = () => {
        return setAPIResponse(false)
    }

    const {
        handleSubmit,
        handleChange,
        handleBlur,
        touched,
        errors,
    } = useFormik({
        initialValues: {
            otp: "",
        },
        validationSchema: schema,
        onSubmit: (values) => {
            console.log(JSON.stringify(values));
            buttonRef.current.disabled = true;
            setLoading(true);
            const loginCall = login.auth(location.state.email, values.otp);

            loginCall.then(response => {
                if (response.status === undefined || response.status === null) {
                    setLoading(false);
                    buttonRef.current.disabled = false;
                    setAPIResponse(true)
                    setAPIMessage(response.message)
                } else {
                    setLoading(false);
                    history.push({
                        pathname: '/dashboard',
                        state: { email: values.email }
                    });
                }
            })



        },
    });

    useEffect(() => {
        inputRef.current.focus();
        readRef.current.value = location.state.email;
    }, [location])

    return <Fragment>
        <div className="centered-form">
            <div className="centered-form__box">
                <div className="mb-3 text-center">
                    <img src={logo} className="img-fluid" width="150" alt="Logo" />
                </div>
                <form onSubmit={handleSubmit} noValidate>
                    <div className="mb-3">
                        <label htmlFor="readEmail" className="form-label">Email</label>
                        <input
                            type="text"
                            name="readEmail"
                            id="readEmail"
                            ref={readRef}
                            className="form-control" readOnly />

                    </div>
                    <div className="mb-3">
                        <label htmlFor="otp" className="form-label">OTP</label>
                        <input
                            type="text"
                            name="otp"
                            id="otp"
                            ref={inputRef}
                            onChange={(e) => { handleChange(e); handleChangeError(e) }}
                            onBlur={handleBlur}
                            className="form-control" placeholder="Enter OTP" required />
                        {touched.otp && errors.otp
                            ? <div className="invalid-feedback">Please enter valid OTP</div>
                            : null}
                        {APIResponse
                            ? <div className="invalid-feedback">{APIMessage}</div>
                            : null}
                    </div>

                    <div className="d-grid gap-2">
                        <button ref={buttonRef} className="btn btn-main">{loading ?
                            <ScaleLoader color={color} loading={loading} css={override} height={15} /> : <span>Login</span>}</button>
                    </div>
                </form>
            </div>
        </div>
    </Fragment>
}

export default OTP

responseloginCall 中,我总是会得到 isAuth: false。 我想使用 isAuth 来保护我的路线。只是为了检查用户是否已登录。 为什么 setUser 没有更新此处的值。

提前致谢...

1 个答案:

答案 0 :(得分:1)

那是因为当您返回 isAuth 值时,new user value 尚未设置。您需要知道 React setState 是异步函数。 只需像这样直接使用布尔值本身:

setUser(true);
return { status: response.data.Status, isAuth: true }

或者在被拒绝的情况下:

setUser(false);
return { status: undefined, message: err, isAuth: false };