createAsyncThunk梳理

createAsyncThunk 是 Redux Toolkit 中的一个核心 API,专门用于简化 Redux 中异步操作(如 API 请求、定时任务等)的管理。它自动生成 pending/fulfilled/rejected 三种 action 类型,并处理异步流程的生命周期,减少开发者手动编写样板代码的工作量。


1. 核心作用

  • 自动生成异步生命周期 Action:根据传入的 type 字符串,自动生成三种 action 类型(如 type/pending, type/fulfilled, type/rejected)。
  • 封装异步逻辑:将异步操作(如 API 调用)封装成一个 thunk action,便于在 Redux 中统一管理。
  • 简化错误处理:通过 try/catch 或 Promise 的 reject 自动捕获错误,并触发 rejected action。

2. 函数签名

import { createAsyncThunk } from '@reduxjs/toolkit';

const asyncThunk = createAsyncThunk(
  type: string, // 基础 action 类型(如 'users/fetch')
  payloadCreator: (arg, thunkAPI) => Promise, // 异步逻辑
  options?: { ... } // 可选配置
);

3. 参数详解

参数 1: type
  • 作用:定义异步操作的基础类型字符串。
  • 动态生成:可以通过函数动态生成 type(例如分页场景):
    createAsyncThunk(
      (page) => `users/fetchPage/${page}`,
      async (page) => { /* ... */ }
    );
    
参数 2: payloadCreator
  • 核心函数:包含异步逻辑(如 API 请求),必须返回一个 Promise。

  • 参数

    • arg:调用 thunk 时传入的参数(如 dispatch(fetchUser(123)) 中的 123)。
    • thunkAPI:包含 Redux 相关方法和工具:
      • dispatch:Redux 的 dispatch 方法。
      • getState:获取当前 Redux 状态。
      • rejectWithValue:将自定义错误传递给 rejected action。
      • signal:AbortController 的信号,用于取消请求。
  • 示例

    const fetchUser = createAsyncThunk(
      'user/fetch',
      async (userId, { rejectWithValue }) => {
        try {
          const response = await api.getUser(userId);
          return response.data; // 传递给 fulfilled action 的 payload
        } catch (err) {
          return rejectWithValue(err.response.data); // 传递给 rejected action 的 payload
        }
      }
    );
    
参数 3: options(可选)
  • 配置项,例如:
    • condition: 控制是否执行异步逻辑(如避免重复请求)。
    • dispatchConditionRejection: 当 condition 返回 false 时,是否触发 rejected action。
    • serializeError: 自定义错误序列化逻辑。

4. 返回值

  • thunk action creator:一个函数,当被 dispatch 时触发异步操作。
  • 返回的 Promise
    • 如果异步成功,Promise 会 resolve 为 fulfilled action 的 payload。
    • 如果失败,Promise 会 reject 为 rejected action 的 error。

5. 处理 Action

在 Redux slice 的 extraReducers 中监听生成的三种 action:

const userSlice = createSlice({
  name: 'user',
  initialState: { data: null, loading: false, error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchUser.fulfilled, (state, action) => {
        state.loading = false;
        state.data = action.payload;
      })
      .addCase(fetchUser.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message; // 或 action.payload(如果用了 rejectWithValue)
      });
  },
});

6. 错误处理最佳实践

使用 rejectWithValue 传递错误信息:

const fetchUser = createAsyncThunk(
  'user/fetch',
  async (userId, { rejectWithValue }) => {
    try {
      const response = await api.getUser(userId);
      return response.data;
    } catch (err) {
      // 返回自定义错误对象(而非默认的 Error 实例)
      return rejectWithValue({
        message: 'Failed to fetch user',
        code: err.response.status,
      });
    }
  }
);

在 reducer 中通过 action.payload 获取错误信息:

.addCase(fetchUser.rejected, (state, action) => {
  state.error = action.payload; // { message: 'Failed...', code: 404 }
});

7. 使用场景

  • 数据获取:从 API 获取数据并更新状态。
  • 表单提交:处理用户提交的异步验证或保存操作。
  • 复杂异步流程:如轮询、取消请求(结合 AbortController)。

8. 注意事项

  1. 不要直接修改 state:在 payloadCreator 中只处理逻辑,状态更新在 extraReducers 中进行。
  2. 错误需明确处理:未捕获的异常会导致 Promise 隐式 reject,但建议显式使用 rejectWithValue
  3. 取消请求:利用 signal 实现请求取消:
    const fetchUser = createAsyncThunk('user/fetch', async (_, { signal }) => {
      const response = await fetch('/api/user', { signal });
      return response.json();
    });
    // 调用 abortController.abort() 取消请求
    

9. 总结

createAsyncThunk 是 Redux Toolkit 中处理异步操作的标准化方案,通过自动生成 action 类型和生命周期管理,显著减少冗余代码。结合 createSliceextraReducers,可以高效实现异步状态管理,尤其适合与 RTK Query 之外的 REST API 交互场景。

你可能感兴趣的:(react.js)