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

异步调用中Redux Store应何时更新?拖拽用createAsyncThunk更新状态延迟如何解决?

问题根源

你当前的实现是等待后端接口请求成功后才更新本地Redux状态,状态更新完全依赖网络请求速度,只要有网络波动或者接口响应慢,就会出现拖拽完成后界面很久才变化的卡顿问题。

解决方案:使用乐观更新

核心逻辑是:拖拽结束后先立即更新本地状态让用户看到效果,再异步发送请求同步到后端,若请求失败再回滚本地状态即可,完全消除等待延迟。

步骤1:修改Slice代码,新增同步操作

const todoBlockSlice = createSlice({
  name: "todoBlockSlice",
  initialState: {
    sections: [] as TodoSectionType[],
    // 存储更新前的状态快照,用于请求失败后回滚
    lastSectionsSnapshot: [] as TodoSectionType[]
  },
  reducers: {
    // 拖拽后立即更新本地状态的同步action
    updateDragStateOptimistic: (state, action) => {
      // 先保存当前状态快照
      state.lastSectionsSnapshot = [...state.sections];
      const { src, dest } = action.payload;
      // 将原来写在fulfilled中的更新逻辑挪到这里
      state.sections = state.sections.map(sec => {
        if (sec.sectionType === src.sectionType) return { ...src };
        if (dest && sec.sectionType === dest.sectionType) return { ...dest };
        return sec;
      })
    },
    // 请求失败时回滚状态的同步action
    rollbackDragState: (state) => {
      state.sections = state.lastSectionsSnapshot;
    }
  },
  extraReducers: (builder) => {
    // 请求失败时自动回滚状态,可自行添加toast等失败提示
    builder.addCase(updateDragNDrop.rejected, (state) => {
      todoBlockSlice.caseReducers.rollbackDragState(state);
    })
  }
})

export const { updateDragStateOptimistic, rollbackDragState } = todoBlockSlice.actions;

步骤2:修改组件的拖拽结束逻辑

// Component code
const onDragEnd = () => {
  // 原有排序逻辑,得到newOrderObjArray
  // 第一步:立即调用同步action更新状态,用户无感知延迟
  dispatch(updateDragStateOptimistic(newOrderObjArray));
  // 第二步:异步发送请求同步后端,不需要等待返回
  dispatch(updateDragNDrop(newOrderObjArray));
}

步骤3:优化异步Thunk的错误处理

//Async Thunk Code
export const updateDragNDrop = createAsyncThunk(
  "todoBlockSlice/updateStateAfterDragNDrop",
  async (sections: any, { rejectWithValue }) => {
    try {
      const sectionsArr = [sections.src, sections.dest]
      await axios.post("http://localhost:8080/updateDnd", sectionsArr);
      return sections;
    } catch (err) {
      return rejectWithValue(err);
    }
  }
);

注意事项

  • 若存在用户短时间内多次拖拽的场景,可以给createAsyncThunk添加AbortController逻辑,取消上一次未完成的请求,避免旧请求失败触发错误回滚。
  • 请求失败时建议添加 toast 等用户提示,避免用户误以为操作成功但后端未保存数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 13:36:10