Redux-toolkit: Access original response body from pending createAsyncThunk

Created on 16 Apr 2020  路  3Comments  路  Source: reduxjs/redux-toolkit

I'm using createAsyncThunk to handle all my api resquests. However, when I'm doing the error handling in the rejected action, I can't seem to access the original body returned from the response.

export const addContact = createAsyncThunk('contacts/addContactStatus', async (obj) => {
  const { data } = await api.post('/contact/', obj);
  return data;
});

const contactsSlice = createSlice({
  name: 'contacts',
  initialState,
  reducers,
   extraReducers: {
    [addContact.pending]: (state) => {
      state.loading = true;
    },
    [addContact.rejected]: (state, action) => {
      state.loading = false;
// I want to use error.response.data.message, which is how I normally 
// handle errors when using Axios directly,
// But I can't seem to access it
      message.error(action.error.message);
    },
    [addContact.fulfilled]: (state, action) => {
      message.success('Contato criado com sucesso');
      state.loading = false;
      state.entities.push(action.payload);
      state.selected.push(action.payload);
    },
}

I really don't want to do the usual try/catch, since it kinda defeats the purpose of having the status action creators, which I think are great for making my code cleaner. I've looked through the past issues, but maybe I'm missing something. It would be great if someone could help me.

Thanks in advance!

Most helpful comment

Hey @will-amaral , your error will be serialized via miniSerializeError unless you specifically catch and return it with rejectWithValue as shown here. There was a good amount of discussion about this behavior and why it was decided to use rejectWithValue that you can skim through here: https://github.com/reduxjs/redux-toolkit/issues/390

In your example, you'd need to do this:

export const addContact = createAsyncThunk('contacts/addContactStatus', async (obj, { rejectWithValue }) => {
try {
  const { data } = await api.post('/contact/', obj);
  return data;
} catch (err) {
  return rejectWithValue(err.response.data); // or whatever path you normally reference
});

All 3 comments

Hey @will-amaral , your error will be serialized via miniSerializeError unless you specifically catch and return it with rejectWithValue as shown here. There was a good amount of discussion about this behavior and why it was decided to use rejectWithValue that you can skim through here: https://github.com/reduxjs/redux-toolkit/issues/390

In your example, you'd need to do this:

export const addContact = createAsyncThunk('contacts/addContactStatus', async (obj, { rejectWithValue }) => {
try {
  const { data } = await api.post('/contact/', obj);
  return data;
} catch (err) {
  return rejectWithValue(err.response.data); // or whatever path you normally reference
});

Yep. createAsyncThunk defaults to the simplest approach, which is the entire successful return value becomes payload, and the entire thrown error gets serialized and included. If you need more specific details, it's up to you to parse and include them in the rejection yourself.

Thanks guys!

Was this page helpful?
0 / 5 - 0 ratings