Javascript 尽管效果不佳,但反应状态落后一步

Javascript 尽管效果不佳,但反应状态落后一步,javascript,reactjs,typescript,ionic-framework,Javascript,Reactjs,Typescript,Ionic Framework,我有一个用户登录的React表单,除了设置成功或不成功的消息外,一切正常。登录后,我将useState变量[res,setRes]的值设置为successful或ususessful,具体取决于用户是否注册。问题是,即使用户已注册且用户名和密码正确,我至少和最多会收到一次无效凭据消息。来自同一用户的后续呼叫将显示正确的消息。我搜索发现state落后了一步,解决方案是使用useffect,但我已经在使用它了。有人能帮我找出问题所在吗?代码如下 export const Login = () =&g

我有一个用户登录的React表单,除了设置成功或不成功的消息外,一切正常。登录后,我将useState变量[res,setRes]的值设置为successful或ususessful,具体取决于用户是否注册。问题是,即使用户已注册且用户名和密码正确,我至少和最多会收到一次无效凭据消息。来自同一用户的后续呼叫将显示正确的消息。我搜索发现state落后了一步,解决方案是使用useffect,但我已经在使用它了。有人能帮我找出问题所在吗?代码如下

export const Login = () => {
    const email = useField('string')
    const password = useField('password')
    const [cred, setCred] = useState({})
    const send = (e:any) => {
        e.preventDefault()
        setCred({'email':email.value, 'password':password.value}) 
            showToast()
    }
    const [toastIsShown, setToastIsShown] = useState(false);

    const showToast = () => {
        setToastIsShown(true);
    }
    const [res,setRes] = useState('')

    const hook = () => {
        axios
        .post('http://localhost:5000/auth', cred)
        .then(response => { 
            console.log('response is ',response.data)
            setRes('Login Successful')
    })
        .catch(err => {
            console.log("error is ",err.response)
            setRes('Invalid username or password')
        })
    }
    useEffect(hook,[cred])
    return (
        <>
            <form onSubmit = {send}>
                <IonText>Enter Name</IonText>
                <br />
                <input {...email} />
                <br />
                <IonText>Enter Password</IonText>
                <br />
                <input {...password} />
                <br />
                <button>Send</button>
            </form>
            <IonToast
                        isOpen={toastIsShown}
                        onDidDismiss={() => setToastIsShown(false)}
                        message={res}
                        duration={3000}
            />
        </>
    )
}
我用的是爱奥尼亚,这就是为什么你会看到土司。此外,该语言是Typescript。 谢谢

当一个组件挂载时,总是调用useEffect钩子,之后每次它的依赖项数组中的值发生变化时,都会调用useEffect钩子。由于空对象可能不是有效的登录,因此当组件装载时,您总是会尝试失败。您可以执行一些简单的验证,如:

cred.email && cred.password && axios.post('http://localhost:5000/auth', cred)...
然而,问题的根源在于你误用了useEffect。登录尝试通常是一次性事件,而不是由于之前的重要操作而产生的副作用。此场景中的副作用发生在尝试登录后,即触发包含结果通知的Toast时:

export const Login = () => {
    const email = useField('string');
    const password = useField('password');
    
    const [res, setRes] = useState('');
    const [toastIsShown, setToastIsShown] = useState(false);

    const send = (e:any) => {
        e.preventDefault();

        const cred = {
            email: email.value,
            password: password.value
        };

        axios
        .post('http://localhost:5000/auth', cred)
        .then(response => { 
            console.log('response is ',response.data)
            setRes('Login Successful');
        })
        .catch(err => {
            console.log("error is ",err.response)
            setRes('Invalid username or password');
        });
    };

    useEffect(() => {
        res && setToastIsShown(true);
    }, [res]);
    
    return (
        ...
    )
}

这只是为了证明更合理地使用useEffect。实际上,我甚至可能不会在这里使用一个,而是在设置res后从内部调用setToastIsShown。当您有两个相关的数据段,这些数据段由多个不相关的方法更新时,useEffect真的很有用。

cred的初始状态是一个空对象,因为const[cred,setCred]=useState{}。如果这是无效的凭据,您将始终收到一个无效呼叫。是否应该仅在存在有效凭据时调用钩子?感谢您的回复。不,无论是否使用有效凭据,都无法调用该钩子。我尝试为cred硬编码有效的用户名密码,但存在相同的问题。