You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在createAsyncThunk的setTimeout中分发action实现延迟计数?

用Redux Toolkit的createAsyncThunk实现延迟加减计数器

我正在学习使用createAsyncThunk,已经做了一个简易计数器应用,有普通的加、减按钮,点击后数值实时增减。现在想新增两个按钮,点击后同样实现加减,但要延迟1秒完成。我已经用非Redux Toolkit的方式实现了这个功能,但不知道怎么用Redux Toolkit来做。我尝试写了部分代码,但不清楚createAsyncThunk的回调该怎么写,之前尝试在回调里分发action没成功,我的代码如下:

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

export const asyncAdd = createAsyncThunk('asyncAdd', async (_, thunkAPI) => {


});
const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0,
    hasError: false,
    isLoading: false,
    users: {},
    todos: {},
  },
  reducers: {
    add: (state, action) => {
      state.count += action.payload;
    },
    sub: (state) => {
      state.count -= 1;
    },
  },
  extraReducers: {
    [asyncAdd.pending]: (state, action) => {
      state.hasError = false;
      state.isLoading = true;
      console.log('PENDING');
    },
    [asyncAdd.fulfilled]: (state, action) => {
      state.hasError = false;
      state.isLoading = false;
      console.log('payload ' + action.payload);
      state.count = action.payload;
      console.log('FULILLED');
    },
    [asyncAdd.rejected]: (state, action) => {
      state.hasError = true;
      state.isLoading = false;
      console.log('REJECTED');
    },
  },
});

export const { add, sub } = counterSlice.actions;
export default counterSlice.reducer;

实现方案

1. 完善异步Thunk函数

createAsyncThunk不需要手动分发action,只需在回调里完成延迟逻辑,返回最终要更新的数值即可。我们需要分别实现延迟加、延迟减两个Thunk:

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

// 延迟加1的异步Thunk
export const asyncAdd = createAsyncThunk('counter/asyncAdd', async (_, thunkAPI) => {
  // 延迟1秒
  await new Promise(resolve => setTimeout(resolve, 1000));
  // 获取当前计数器数值
  const currentCount = thunkAPI.getState().counter.count;
  // 返回新的数值
  return currentCount + 1;
});

// 延迟减1的异步Thunk
export const asyncSub = createAsyncThunk('counter/asyncSub', async (_, thunkAPI) => {
  await new Promise(resolve => setTimeout(resolve, 1000));
  const currentCount = thunkAPI.getState().counter.count;
  return currentCount - 1;
});

2. 在extraReducers中处理异步状态

推荐使用Redux Toolkit官方推荐的builder链式写法,类型更安全且可读性更高:

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0,
    hasError: false,
    isLoading: false,
  },
  reducers: {
    add: (state, action) => {
      state.count += action.payload;
    },
    sub: (state) => {
      state.count -= 1;
    },
  },
  extraReducers: (builder) => {
    // 处理asyncAdd的三种状态
    builder
      .addCase(asyncAdd.pending, (state) => {
        state.isLoading = true;
        state.hasError = false;
      })
      .addCase(asyncAdd.fulfilled, (state, action) => {
        state.isLoading = false;
        state.count = action.payload;
      })
      .addCase(asyncAdd.rejected, (state) => {
        state.isLoading = false;
        state.hasError = true;
      })
      // 处理asyncSub的三种状态
      .addCase(asyncSub.pending, (state) => {
        state.isLoading = true;
        state.hasError = false;
      })
      .addCase(asyncSub.fulfilled, (state, action) => {
        state.isLoading = false;
        state.count = action.payload;
      })
      .addCase(asyncSub.rejected, (state) => {
        state.isLoading = false;
        state.hasError = true;
      });
  },
});

export const { add, sub } = counterSlice.actions;
export default counterSlice.reducer;

3. 组件中调用异步Thunk

在组件里通过useDispatch分发异步Thunk即可,同时可以用isLoading状态防止重复点击:

import { useDispatch, useSelector } from 'react-redux';
import { add, sub, asyncAdd, asyncSub } from './counterSlice';

function Counter() {
  const { count, isLoading } = useSelector(state => state.counter);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>当前数值:{count}</h1>
      <button onClick={() => dispatch(add(1))}>普通加1</button>
      <button onClick={() => dispatch(sub())}>普通减1</button>
      <button onClick={() => dispatch(asyncAdd())} disabled={isLoading}>延迟加1(1秒)</button>
      <button onClick={() => dispatch(asyncSub())} disabled={isLoading}>延迟减1(1秒)</button>
      {isLoading && <p>处理中...</p>}
    </div>
  );
}

核心注意事项

  • 不要在createAsyncThunk的回调里手动分发action,Thunk会自动根据异步状态生成对应action,我们只需返回最终数据。
  • 如需获取当前状态,使用thunkAPI.getState()方法即可。
  • 利用isLoading状态禁用按钮,避免用户重复触发异步操作。

内容的提问来源于stack exchange,提问作者Gautham Muralidharan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:55:31