【问题标题】:How to convert .then .catch to async/await如何将 .then .catch 转换为 async/await
【发布时间】:2021-04-10 17:56:30
【问题描述】:

使用 React/Redux 前端和我自己的 nodejs/express api 处理登录表单/注销按钮。登录表单有问题。大多数时候它工作得很好,但我经常犯错误。第一个错误是forbidden,它告诉我在发送userDetails 请求之前,用户还没有完全通过身份验证。

还有一个 bug,Redux 没有改变用户的角色,我需要动态渲染导航。我认为将 handleLogin 转换为 async/await 将是解决方案,但我相信我做得不对。

import React from 'react';
import { login, userDetails } from '../axios/homeApi';
import { useForm } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { setLogin, setRole } from '../redux/actions';
const LoginForm = () => {
const { handleSubmit, register, errors } = useForm();
const dispatch = useDispatch();

const handleLogin = values => {
    login(values.email, values.password)
    .then(res => {
        const token = res.data.token;
        window.localStorage.setItem('auth', token);
        dispatch(setLogin({ loggedIn: true }));
        userDetails()
        .then(res => {
            const role = res.data.data.role;
            dispatch (setRole({ role }));
        })
    })
}

return (
    <div>
        <form action="" onSubmit={handleSubmit(handleLogin)} className="footer-form">
            <input
                type="email"
                placeholder="Enter Email Here"
                name="email"
                ref={register({ required: "Required Field" })}
            />
            <input
                type="password"
                placeholder="Enter Password Here"
                name="password"
                ref={register({
                    required: "Required Field",
                    minLength: { value: 6, message: "Minimum Length: 6 Characters" }
                })}
            />
            {errors.password && errors.password.message}
            {errors.email && errors.email.message}
            <input type="submit" value="Login" />
        </form>
    </div>
)
}

export default LoginForm;

这是我将 handleLogin 转换为 async/await 的最佳尝试。我试图了解我应该如何从这些调用中提取数据。

const handleLogin = async values => {
    try {
        const {data: {token}} = await login(values.email, values.password)
        window.localStorage.setItem('auth', token);
        console.log(token);
        const user = await userDetails();
        await dispatch(setLogin({ loggedIn: true}))
        await dispatch(setRole(user.data.data.role))
    } catch(err) {
        console.log(err)
    }
}

对此的任何帮助/指导将不胜感激。

【问题讨论】:

  • dispatch 不可等待。
  • 您应该考虑改用 TypeScript,因为了解类型(“形状”)并知道什么是可等待的,什么不是可以让编写现代 JavaScript 变得更加容易。

标签: javascript async-await react-redux


【解决方案1】:

你必须想,当你使用await时,变量值与没有await时返回到res的变量值是一样的。

如果你有:

login(values.email, values.password)
    .then(res => { 
     })

这就像:

var login = await login(values.email, values.password);

所以使用这个逻辑,这个:

login(values.email, values.password)
    .then(res => {
        const token = res.data.token;
        // whatever
        userDetails()
        .then(res => {
            const role = res.data.data.role;
            // whatever
        })
    })

变成:

var login = await login(values.email, values.password)
const token = login.data.token;
// do whatever
var userDetails = await userDetails()
const role = userDetails.data.data.role;
// whatever

检查此示例的工作原理。代码是“相同的”。一个使用.then,另一个使用await

runThenFunction();

runAwaitFunction();

function runThenFunction(){
  console.log("Enter then function")
  this.returnPromise(2000).then(res => {
    console.log(res);
    this.returnPromise(1000).then(res => {
      console.log(res);
    });
  });
  //You can log here and it will be displayed before the promise has been resolved
  console.log("Exit then function")
}

async function runAwaitFunction(){
  console.log("Enter await function")
  var firstStop = await returnPromise(1000);
  console.log(firstStop)
  var secondStop = await returnPromise(4000);
  console.log(secondStop)
  // Using await the code "stops" until promise is resolved
  console.log("Exit await function")
}

function returnPromise(time){
  return new Promise(resolve => setTimeout(() => resolve("hello: "+time+"ms later."), time));
}

【讨论】:

  • 仍然收到未经授权的错误。检查了瀑布,等待按预期工作。但我没有及时获得我需要的登录信息。设置超时可能是一种方法,因为登录调用平均需要 4 毫秒,但我很好奇这对于生产质量应用程序是否是一种好的做法。
  • @AaronToliver 我建议你尽你所能避免超时!此处的最佳做法是等待响应完成,而不是等待任意持续时间到期。
【解决方案2】:

看起来您可能已经有了答案,但在我看来这可能是因为您没有等待 setLogin 的调度完成。我不知道您的 setLogin 方法是如何设置的,但它必须是一个 thunk。我发现下面的帖子很好地解释了它。

How to return a promise from an action using thunk and useDispatch (react-redux hooks)?

【讨论】:

    【解决方案3】:

    考虑任何具有then 属性的对象,这是一个接受回调作为其第一个参数的函数,例如:

    let obj = {
      then: callback => callback('hello')
    };
    

    await 将任何此类对象转换为then 提供给回调的值。因此:

    (await obj) === 'hello'
    

    在您的示例中,有两个实例需要将值返回到 then 回调:

    login(...).then(res => { /* got res */ });
    

    userDetails().then(res => { /* got res */ });
    

    await 简单地视为将值返回到对象的then 回调的一种方式!在这种情况下,对象是login(...)userDetails() 的结果,您可以转换为:

    let res = await login(...);
    

    let res = await userDetails();
    

    你可以看到这也节省了很多缩进,这是人们喜欢使用async/await的众多原因之一!

    这些从 then-callback-value 到 await 的转换,当插入到您的代码中时,如下所示:

    const handleLogin = async values => {
      
      let loginRes = await login(values.email, values.password);
      let token = loginRes.data.token;
      window.localStorage.setItem('auth', token);
      dispatch(setLogin({ loggedIn: true }));
      
      let userDetailsRes = await userDetails();
      let role = userDetailsRes.data.data.role;
      dispatch(setRole({ role }));
      
    };
    

    请注意,该函数必须标记为async,并且我已将res 重命名为更具体的名称,因为这两个响应现在存在于完全相同的范围内,并且需要彼此区分开来。

    总体而言,每当您使用then 获取回调中的某些值时,您都可以转换为更优雅的await 等效项。

    【讨论】:

    • 这几乎完全符合我所做的。仍然收到 userDetails() 的禁止错误。 const handleLogin = async values => { let signin = await login(values.email, values.password);常量令牌 = signin.data.token; window.localStorage.setItem('auth', token);调度(setLogin({登录:真}));常量用户 = 等待用户详细信息();控制台.log(user.data.role);我有另一个解决方案,但它不涉及这个。这真太了不起了。我打算用这些知识重构这个应用程序。
    猜你喜欢
    • 2019-12-14
    • 2018-11-24
    • 2021-10-19
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 2016-11-10
    • 2017-11-08
    • 2020-01-02
    相关资源
    最近更新 更多