Redux 工具包 thunk 操作通用错误处理程序

Redux toolkit thunk action generic error handler

我很喜欢 redux-toolkit,但我想知道是否有办法为任何被拒绝的 thunk 添加通用错误处理程序?就像浏览器有您可以收听的 unhandledrejection 事件一样,我想向我的错误跟踪器报告任何被拒绝的承诺。

创建一个错误状态切片来保存全局错误并使用 isRejected 匹配函数来检查一个动作是否是来自 createAsyncThunk 承诺生命周期的 'rejected' 动作创建者。

例如

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());

最终状态输出:

state: {
  error: { message: 'some thunk rejected' },
  a: { name: '' },
  b: { name: '' },
  c: { name: '' }
}

thunkAthunkB是'rejected'动作,可以在errorSlicereducer集中处理被拒绝的动作。

听起来您想在每次 thunk 被拒绝时 运行 产生副作用(向服务器发送消息)。我建议查看 our new "listener middleware" for Redux Toolkit,它特别允许您在调度某些操作时触发额外的逻辑。

侦听器中间件目前是一个单独的 @rtk-incubator/action-listener-middleware 包,因为我们一直在对其 API 进行迭代,但截至今天 API 已稳定,我们计划正式发布它很快就会成为 RTK 1.8 的一部分。您今天可以在该包中使用它,并在该版本发布后立即切换为从 RTK 导入它。

它可能是这样的:

// 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
  },
})