timolins / react-hot-toast

Smoking Hot React Notifications 🔥
https://react-hot-toast.com
MIT License
9.78k stars 331 forks source link

Redux - How to use react-hot-toast with async await Axios call #40

Closed Jared-Dahlke closed 1 year ago

Jared-Dahlke commented 3 years ago

hey guys, I saw the other question about this but it did not help me. I have tried multiple ways to get this to work but cannot seem to make it work.

I tried this:

export const postVersionBulkAction = (args) => {
    let url = `${apiBase}/smart-list/version/${args.versionId}/action`
    let promise = queue.wrap(async (dispatch) => {
        let params = { iabCategoriesActions: args.iabCategoriesActions }
        const result = await axios.patch(url, params)
        if (result.status === 200) {
        }
    })
    toast.promise(promise, {
        loading: 'Saving...',
        success: 'saved',
        error: 'error'
    })
}

but that gives me an error: 'TypeError: promise.then is not a function'

I've also tried this:

export const postVersionBulkAction = (args) => {
    let url = `${apiBase}/smart-list/version/${args.versionId}/action`
    return queue.wrap(async (dispatch) => {
        try {
            let params = { iabCategoriesActions: args.iabCategoriesActions }
            const result = await axios.patch(url, params)
            toast.promise(result, {
                loading: 'Saving...',
                success: 'saved',
                error: 'error'
            })
        } catch (error) {
            alert(error)
        }
    })
}

but i get 'promise.then is not a function' error on that one too.

I've also tried calling it like this:

    const promise = props.postVersionBulkAction(params)     
        toast.promise(promise, {
            loading: 'Saving...',
            success: <b>saved!</b>,
            error: <b>Could not apply.</b>
        })

but that way always fires the success toast even if it fails.

Any idea how i could make this work?

PS. thanks for the awesome product! Other than this problem it has helped me so much, and I have succesfully removed thousands of lines of redux boilerplate because of this library. thanks again

timolins commented 3 years ago

Hey! I'm not entirely sure what is going on but I think it should work like this:

const promise = axios.patch(url, params)

toast.promise(promise, {
  loading: 'Saving...',
  success: <b>saved!</b>,
  error: <b>Could not apply.</b>
})

const result = await promise
Jared-Dahlke commented 3 years ago

Hey! I'm not entirely sure what is going on but I think it should work like this:

const promise = axios.patch(url, params)

toast.promise(promise, {
  loading: 'Saving...',
  success: <b>saved!</b>,
  error: <b>Could not apply.</b>
})

const result = await promise

It is still popping up as a success when I try your way even when the network call is failing with a 404:

export const postVersionBulkAction = (args) => {    
    return async (dispatch) => {        
        const promise = axios.patch(badUrl,  params )
        toast.promise(promise, {
            loading: 'Saving...',
            success: 'saved',
            error: 'error'
        })

        const result = await promise
    }
}

it pops up a success immediately

Edited: removed some of the extraneous stuff from the function to make it easier for someone to diagnose

lsbyerley commented 3 years ago

@JaredDahlke did you ever resolve this? I am also seeing this error when trying to write a unit test for a component using toast.promise

ingusjan commented 3 years ago

Have you tried ensuring your .catch was first and .then following it? Weirdly enough, that fixed this same issue for me.

 const callMyFunction = callFunction({ username: this.state.username })
      .catch((error) => {
        // Getting the Error details.
        console.error(error.message);
        return error.message;
      })
      .then((res) => {
        console.log(res);
        refreshData();
      });

    toast.promise(callMyFunction, {
      loading: "Loading...",
      success: "Everything went smoothly.",
      error: "Uh oh, there was an error!",
    });

(I know this isn't an Axios example, but the promise structure is relatively the same)

gamino97 commented 3 years ago

The toast.promise function returns the promise, so you could use something like this:

const callMyFunction = toast.promise(callFunction({ username: this.state.username }), {
      loading: "Loading...",
      success: "Everything went smoothly.",
      error: "Uh oh, there was an error!",
    });
callMyFunction.then((res) => {
    console.log(res);
    refreshData();
})
 .catch((error) => {
        // Getting the Error details.
        console.error(error.message);
        return error.message;
      });
gugocharade commented 2 years ago

This worked for me

const res = fetch(apiUrl);

    toast.promise(res, {
      loading: 'Loading ...',
      success: (data) => {
        if (!data.ok) throw new Error(data.statusText);
        return 'Everything went smoothly.';
      },
      error: (err)=> err.message,
    });
tlhabane commented 2 years ago

Here is what works for

const promise = axios.patch(url, params)

toast.promise(promise, {
  loading: 'Saving...',
  success: <b>saved!</b>,
  error: <b>Could not apply.</b>
},
, {
   style: {
    minWidth: '250px',
   }
 }
)
.then((r) => r)
.catch((error) => error);
amanzrx4 commented 2 years ago

In case anyone using firebase:

 toast.promise(
      createUserWithEmailAndPassword(authInstance, email, password),
      {
        loading: "loading...",
        success: (result) => `success, ${result.user}`,
        error: (e) => `error ${e.message}`,
      }
    );
axquired24 commented 2 years ago

In my case, make sure you throw an error after doing a catch

This Work for me

 const callMyFunction = callFunction({ username: this.state.username })
      .catch((error) => {
        // Getting the Error details.
        console.error(error.message);
        throw error; // throw again after you catch
      })
      .then((res) => {
        console.log(res);
        refreshData();
      });

    toast.promise(callMyFunction, {
      loading: "Loading...",
      success: "Everything went smoothly.",
      error: "Uh oh, there was an error!",
    });
TheJazzDev commented 1 year ago

In case anyone using firebase:

 toast.promise(
      createUserWithEmailAndPassword(authInstance, email, password),
      {
        loading: "loading...",
        success: (result) => `success, ${result.user}`,
        error: (e) => `error ${e.message}`,
      }
    );

Thanks a lot, this work for me...

a0m0rajab commented 1 year ago

This is a bit tricky due to the next:

I solved this by doing the next: throwing an error from the my toast code if the server was not sending the expected/ok statues.

toast.promise(fetch(someURL), {
      loading: "Loading ...",
      success: data => {
        if (!data.ok) { //here you can that this will throw the error from the returned data. Usually it's treated as normal thing.
          throw new Error(`Statues code ${data.status}`);
        }
        return "Everything went good";
      },
      error: e => {
        return `Uh oh, there was an error! ${e.message}`;
      },
    })