I need function in redux-toolkit to fetch all data from others slices.
I have this code:
export const getAllData = createAsyncThunk(
'fetchRoot/getAllData',
async (_, { dispatch, rejectWithValue }) => {
const promises = [dispatch(getUsers()), dispatch(getSettings()), dispatch(getClients())];
Promise.all(promises)
.then((res: any) => {
// for (const promise of res) {
// console.log('SSS', promise);
// if (promise.meta.rejectedWithValue) {
// return rejectWithValue(promise.payload);
// }
}
})
.catch((err) => {
console.log(err);
});
}
);
My question: if one of slice fetch function (example: getUsers()) is rejected, how to reject promise.all?
getUsers() function and extraReducers:
export const getUsers = createAsyncThunk('users/getUsers', async (_, { rejectWithValue }) => {
try {
const res = await agent.Users.getAll();
return await res.data;
} catch (err) {
return rejectWithValue(err);
}
});
extraReducers: (builder) => {
builder
// GetUsers lifecycle ===================================
.addCase(getUsers.pending, (state) => {
state.apiState.loading = true;
state.apiState.error = null;
})
.addCase(getUsers.fulfilled, (state, { payload }) => {
state.apiState.loading = false;
state.data = payload;
})
.addCase(getUsers.rejected, (state, { payload }) => {
state.apiState.loading = false;
state.apiState.error = payload;
})
You have it basically right. Once the Promise.all(promises)
has resolved you will have an array containing the resolved value of each of your individual thunks.
The individual promises will always resolve and will never reject. They will resolve to either a fulfilled
action or a rejected
action. In some cases, it will make sense to use the unwrap()
property which causes rejected actions to throw errors. But looking at the .meta
property will work too.
You can check your action with the isRejected
or isRejectedWithValue
functions which serve as type guards, that way you won't have any TypeScript errors when accessing properties like action.meta.rejectedWithValue
.
The hard part here is trying to return rejectWithValue()
from inside a loop. I would recommend unwrapping to throw an error instead.
import { createAsyncThunk, unwrapResult } from "@reduxjs/toolkit";
export const getAllData = createAsyncThunk(
"fetchRoot/getAllData",
async (_, { dispatch }) => {
const promises = [dispatch(getUsers()), dispatch(getSettings()), dispatch(getClients())];
const actions = await Promise.all(promises);
return actions.map(unwrapResult);
}
);
Note that there is no reason to try
/catch
in your getUsers
thunk if you are going to rejectWithValue
with the entire caught error object. Just let the error be thrown.
export const getUsers = createAsyncThunk('users/getUsers', async () => {
const res = await agent.Users.getAll();
return res.data;
});