I'm enjoying redux-toolkit, but I'm wondering if there is a way to add a generic error handler for any rejected thunk? Just like the browser has the unhandledrejection event you can listen to, I'd like to report any rejected promises to my error tracker.
I'm enjoying redux-toolkit, but I'm wondering if there is a way to add a generic error handler for any rejected thunk? Just like the browser has the unhandledrejection event you can listen to, I'd like to report any rejected promises to my error tracker.
Share edited Feb 23, 2022 at 3:18 Lin Du 103k136 gold badges334 silver badges567 bronze badges asked Feb 23, 2022 at 0:22 Robin ClowersRobin Clowers 2,16020 silver badges28 bronze badges2 Answers
Reset to default 7It sounds like you want to run a side effect (sending a message to the server) every time a thunk is rejected. I would suggest looking at our new "listener middleware" for Redux Toolkit, which specifically lets you trigger additional logic when certain actions are dispatched.
The listener middleware is currently a separate @rtk-incubator/action-listener-middleware
package as we've been iterating on its API, but as of today the API is stable and we plan to officially release it as part of RTK 1.8 shortly. You can use it in that package today, and switch to importing it from RTK as soon as that release es out.
Here's what it might look like:
// app/listenerMiddleware.js
import { isRejected } from '@reduxjs/toolkit';
import { createListenerMiddleware } from '@rtk-incubator/action-listener-middleware';
const listenerMiddleware = createListenerMiddleware()
listenerMiddleware.startListening({
matcher: isRejected,
effect: async (action, listenerApi) => {
// send a message to the server here containing info from the action
},
})
Create an error state slice hold the global error and use isRejected matching function to check whether an action is a 'rejected' action creator from the createAsyncThunk
promise lifecycle.
E.g.
import { configureStore, createAsyncThunk, createSlice, isRejected, isRejectedWithValue } from '@reduxjs/toolkit';
const thunkA = createAsyncThunk('a', async (_, thunkAPI) => {
return thunkAPI.rejectWithValue('error a');
});
const thunkB = createAsyncThunk('b', async (_, thunkAPI) => {
return Promise.reject('error b');
});
const thunkC = createAsyncThunk('c', async (_, thunkAPI) => {
return { name: 'c' };
});
const thunkASlice = createSlice({
name: 'thunkA',
initialState: { name: '' },
reducers: {},
extraReducers: (builder) => {
builder.addCase(thunkA.fulfilled, (state, action) => {
state.name = (action.payload as any).name;
});
},
});
const thunkBSlice = createSlice({
name: 'thunkB',
initialState: { name: '' },
reducers: {},
extraReducers: (builder) => {
builder.addCase(thunkA.fulfilled, (state, action) => {
state.name = (action.payload as any).name;
});
},
});
const thunkCSlice = createSlice({
name: 'thunkC',
initialState: { name: '' },
reducers: {},
extraReducers: (builder) => {
builder.addCase(thunkA.fulfilled, (state, action) => {
state.name = (action.payload as any).name;
});
},
});
const errorSlice = createSlice({
name: 'error',
initialState: {
message: '',
},
reducers: {},
extraReducers: (builder) => {
builder.addMatcher(isRejected, (state, action) => {
// global error handle reducer
state.message = 'some thunk rejected';
});
},
});
const store = configureStore({
reducer: {
error: errorSlice.reducer,
a: thunkASlice.reducer,
b: thunkBSlice.reducer,
c: thunkCSlice.reducer,
},
});
store.subscribe(() => {
console.log('state:', store.getState());
});
// store.dispatch(thunkA());
store.dispatch(thunkB());
store.dispatch(thunkC());
Final state output:
state: {
error: { message: 'some thunk rejected' },
a: { name: '' },
b: { name: '' },
c: { name: '' }
}
thunkA
and thunkB
are 'rejected' actions, you can handle the rejected action in the errorSlice
reducer centralized.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744820642a4595593.html
评论列表(0条)