如何在 useReducer 钩子中发出异步服务器请求?

Posted

技术标签:

【中文标题】如何在 useReducer 钩子中发出异步服务器请求?【英文标题】:How to make a asynchronous sever request in a useReduce hook? 【发布时间】:2021-07-26 21:23:04 【问题描述】:

我已经使用 useContext 设置了一个 useReducer 挂钩来接收电子邮件和密码以用于登录目的,我已经创建了一个组件来从服务器获取身份验证令牌。我目前无法弄清楚如何使用返回的 accessToken 更新减速器。

减速器

    export const loginInitialState = 
      isLogin: false,
      accessToken: '',
     as LoginInitialState
    
//this is the part that is not working
    export const loginReducer = async (
      state: LoginInitialState,
       actionType, email, password : LoginPayload
    ) => 
      switch (actionType) 
        case 'login':
          const data = await loginRequest(email, password)
          console.log(data)
          return 
            ...data,
          
        case 'logout':
          return 
            ...loginInitialState,
          
      
    

使用上下文

export const LoginStateContext = createContext<LoginStateContextProps>(false)
export const LoginDispatchContext = createContext<LoginDispatchContextProps>(
  () => 
)
export const AccessTokenContext = createContext<AccessTokenProps>('')

export const LoginProvider = (
  children,
: React.PropsWithChildren<unknown>) => 
  //@ts-ignore
  const [isLogin, dispatchLogin] = useReducer(loginReducer, loginInitialState)

  return (
    <AccessTokenContext.Provider value=isLogin.accessToken>
      <LoginDispatchContext.Provider value=dispatchLogin>
        <LoginStateContext.Provider value=isLogin.isLogin>
          children
        </LoginStateContext.Provider>
      </LoginDispatchContext.Provider>
    </AccessTokenContext.Provider>
  )

获取请求

export const loginRequest = async (email?: string, password?: string) => 
  let data: any
  await axios
    .post(`blah blah blah`, 
      emailAddress: email,
      password: password,
    )
    .then((res) => 
      data = res.data
    )
  if (data) 
    return 
      isLogin: true,
      accessToken: data.accessToken,
    
   else 
    return  ...loginInitialState 
  

调度点

const onLoginClick = () => 
    dispatchLogin( actionType: 'login', email: email, password: password )
  

我可以通过控制台记录返回的身份验证密钥,但我无法让 reducer 更新到返回的状态。

【问题讨论】:

我假设您的意思是标题中的“异步”而不是“同步”? 啊,是我的错,谢谢 【参考方案1】:

不可能在useReducer 中执行异步操作。如果我没记错的话,你的状态就是一个承诺。

您必须做的是在外部执行该操作并通过调度传递数据。所以,你的 reducer 只处理数据。

此外,通过在外部抽象您的逻辑,您可能会对单元测试感兴趣,因此可以模拟不同场景的响应。如果它不适用,也许你想保持你的 API 隔离,不知道,每个应用程序/团队/开发人员都有自己的用例。

最后一点,如果您使用async/await,请不要使用then。要么是一个,要么是另一个。

【讨论】:

我已将其更改为 useState 挂钩,只需在所需目的地设置状态即可解决问题,但感谢您的回复!

以上是关于如何在 useReducer 钩子中发出异步服务器请求?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 useReducer 钩子测试组件?

在表单控制输入中反应 js useReducer 钩子

React 用 useReducer 替换 useState,同时还使用自定义钩子

React TS useContext useReducer 钩子

React useReducer 异步数据获取

使用带有 useReducer() 钩子的 React Context API 有啥优点和缺点?