简体   繁体   English

如何从 redux thunk 操作返回一个承诺并在组件中使用它

[英]How to return a promise from redux thunk action and consume it in component

I am using React+Redux+Redux Thunk + Firebase authentication.我正在使用 React+Redux+Redux Thunk + Firebase 身份验证。 Writing code in Typescript.在 Typescript 中编写代码。 My action is:我的行动是:

//Type for redux-thunk. return type for rdux-thunk action creators
type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  IStoreState, //my store state
  null,
  Action<userActionTypes>
>

export const signInWithEmailAndPasword =(email:string, pasword:string): AppThunk=>{
  return async (dispatch)=>{
    auth.signInWithEmailAndPassword(email, pasword).then(response=>{
      if(response.user){
        const docRef = db.collection("users").doc(response.user.uid);
          docRef.get().then(function(doc) {
            if (doc.exists) {
              const userData = doc.data(); //user data from firebase DB
               //if user exists in DB, dispatch
               dispatch({
                type: userActionTypes.SIGN_IN_USER,
                payload: userData
              })
              return userData;
            } else {
                // doc.data() will be undefined in this case
                console.log("No such document!");
            }
        }).catch(function(error) {
            console.log("Error getting document:", error);
        });
      }
    })
    .catch(err=> dispatch(setUserError(err.message)))
  }
}

My SignIn component, where i am dispatching this above action:我的 SignIn 组件,我将在其中发送上述操作:

import React, { useState } from 'react'
//some other imports
//...
//
import { useDispatch, useSelector } from 'react-redux';
import { signInWithEmailAndPasword } from '../../redux/actions/userActions';


interface ISignInState {
  email: string;
  password: string;
}
const SignIn = (props:any) => {

  const [values, setValues] = useState<ISignInState>({ email: '', password: '' })

  const dispatch = useDispatch();

  const handleInputChange = (e: React.FormEvent<HTMLInputElement>): void => {
    const { name, value } = e.currentTarget;
    setValues({ ...values, [name]: value })
  }

  const handleFormSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    const { email, password } = values;
    dispatch(signInWithEmailAndPasword(email, password))
//// -> gives error: Property 'then' does not exist on 
//// type 'ThunkAction<void, IStoreState, null, Action<userActionTypes>>'
    .then(()=>{ 
      props.history.push('/');
      setValues({ email: '', password: '' })
    })

  }

  return (<div>Sign in UI JSX stuff</div>)

So when i try to use .then() after dispatch(signInWithEmailAndPasword(email, password)) it gives an error Property 'then' does not exist on type 'ThunkAction<void, IStoreState, null, Action<userActionTypes>>' So how can i return promise from redux action and chain a .then() on it?因此,当我尝试在dispatch(signInWithEmailAndPasword(email, password)) .then()之后使用 .then() 时,它给出了一个错误Property 'then' does not exist on type 'ThunkAction<void, IStoreState, null, Action<userActionTypes>>'那么如何我可以从 redux 操作返回承诺并在其上链接.then()吗? I always assumed that thunk actions return promises by default.我一直认为默认情况下 thunk 操作会返回 promises。 Thanks for your help Edit: Temporary soluton was to use any as return type of above action:感谢您的帮助 编辑:临时解决方案是使用any作为上述操作的返回类型:

export const signInWithEmailAndPasword = (email:string, pasword:string):any =>{
  return async (dispatch: any)=>{
    try {
      const response = await auth.signInWithEmailAndPassword(email, pasword)
      if(response.user){
        const userInDb = await getUserFromDB(response.user)
        dispatch(userSignIn(userInDb))
        return userInDb
      }
    } catch (error) {
      dispatch(setUserError(error.message))
    }
  }
}

But I don't want to use any但我不想使用any

Just add return before this line:只需在此行之前添加return

auth.signInWithEmailAndPassword(email, pasword).then(response=>{

So it would be:所以它会是:

export const signInWithEmailAndPasword =(email:string, pasword:string): AppThunk=>{
  return async (dispatch)=>{
    return auth.signInWithEmailAndPassword(email, pasword).then(response=>{

It should work.它应该工作。

AppThunk<Promise<void>>


You need to explicitly declare the AppThunks return type, which in this case should be a Promise containing nothing.您需要显式声明 AppThunks 返回类型,在本例中应该是一个什么都不包含的Promise You have already made it async so just make sure to enter the correct AppThunk return type您已经将其设为异步,因此只需确保输入正确的 AppThunk 返回类型

export const signInWithEmailAndPassword = (email: string, password: string): AppThunk<Promise<void>> => {
  return async (dispatch) => {
      // do stuff
  }
}

Thunks return functions, not promises. Thunks 返回函数,而不是承诺。 For this you could look at redux-promise .为此,您可以查看redux-promise But to be honest if your doing something this complex you would be much better off using redux-saga .但老实说,如果你做这么复杂的事情,你最好使用redux-saga

Another approach would be to use the concepts behind redux-api-middleware to create your own custom redux middleware.另一种方法是使用redux-api-middleware背后的概念来创建您自己的自定义 redux 中间件。 I have done this in the past to connect a message queue to redux.我过去这样做是为了将消息队列连接到 redux。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM