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

Redux中如何标识方法调用成功?TypeScript报错求助

问题原因

Redux Toolkit的reducer(CaseReducer)不允许返回布尔值。根据类型定义,reducer的返回值只能是以下三种之一:

  • void:修改Immer包装的state(draft)后不返回任何值(Immer自动处理state更新)
  • 完整的StrategySlice状态对象(直接返回新state)
  • Immer的WritableDraft<StrategySlice>类型对象

你返回boolean不符合任何类型要求,因此触发TypeScript错误。

最佳实现方案

要避免静默失败并实现错误处理,推荐以下几种方案:

方案一:使用createAsyncThunk(推荐)

虽然你的逻辑是同步的,但createAsyncThunk可以让你明确返回操作结果,还会自动生成对应状态的action,组件能直接获取成功/失败反馈,完美解决静默失败问题。

代码实现

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

// 定义异步thunk,内部执行同步删除逻辑
export const deleteStage = createAsyncThunk(
  'strategy/deleteStage',
  (payload: { strategyId: string; stageId: string }) => {
    // 这里复用你的存在性校验逻辑
    const strategyIndex = findStrategyIndexById({ strategies: [] }, payload.strategyId); // 替换为实际state获取方式
    
    if (strategyIndex !== -1) {
      return { success: true, ...payload };
    }
    return { success: false };
  }
);

const strategySlice = createSlice({
  name: 'strategy',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(deleteStage.fulfilled, (state, action) => {
      if (action.payload.success) {
        const { strategyId, stageId } = action.payload;
        const strategyIndex = findStrategyIndexById(state, strategyId);
        if (strategyIndex !== -1) {
          state.strategies[strategyIndex].stages = state.strategies[strategyIndex].stages.filter(
            stage => stage.id !== stageId
          );
        }
      }
    });
  }
});

export default strategySlice.reducer;

组件中使用

import { useDispatch } from 'react-redux';
import { deleteStage } from './strategySlice';

const YourComponent = () => {
  const dispatch = useDispatch();

  const handleDelete = async (strategyId: string, stageId: string) => {
    try {
      const result = await dispatch(deleteStage({ strategyId, stageId })).unwrap();
      if (result.success) {
        console.log('删除成功');
      } else {
        console.log('未找到目标策略,删除失败');
      }
    } catch (err) {
      console.error('删除操作出错:', err);
    }
  };

  return <button onClick={() => handleDelete('strat-1', 'stage-2')}>删除阶段</button>;
};

方案二:在state中添加操作状态字段

如果不想用thunk,可以在slice的state中新增一个字段记录最近一次操作的结果,组件通过useSelector读取该状态判断操作是否成功。

代码实现

首先修改state结构:

interface StrategySlice {
  strategies: Strategy[];
  lastOperationStatus: 'idle' | 'success' | 'failed';
}

const initialState: StrategySlice = {
  strategies: [],
  lastOperationStatus: 'idle'
};

然后更新slice:

const strategySlice = createSlice({
  name: 'strategy',
  initialState,
  reducers: {
    deleteStage: (state, action: PayloadAction<{ strategyId: string; stageId: string }>) => {
      const { strategyId, stageId } = action.payload;
      const strategyIndex = findStrategyIndexById(state, strategyId);

      if (strategyIndex !== -1) {
        state.strategies[strategyIndex].stages = state.strategies[strategyIndex].stages.filter(
          stage => stage.id !== stageId
        );
        state.lastOperationStatus = 'success';
      } else {
        state.lastOperationStatus = 'failed';
      }
    },
    resetOperationStatus: (state) => {
      state.lastOperationStatus = 'idle';
    }
  }
});

export const { deleteStage, resetOperationStatus } = strategySlice.actions;
export default strategySlice.reducer;

组件中使用

import { useDispatch, useSelector } from 'react-redux';
import { deleteStage, resetOperationStatus } from './strategySlice';
import { useEffect } from 'react';

const YourComponent = () => {
  const dispatch = useDispatch();
  const operationStatus = useSelector(state => state.strategy.lastOperationStatus);

  const handleDelete = (strategyId: string, stageId: string) => {
    dispatch(deleteStage({ strategyId, stageId }));
  };

  // 监听操作状态,处理后重置状态
  useEffect(() => {
    if (operationStatus === 'success') {
      console.log('删除成功');
      dispatch(resetOperationStatus());
    } else if (operationStatus === 'failed') {
      console.log('删除失败');
      dispatch(resetOperationStatus());
    }
  }, [operationStatus, dispatch]);

  return <button onClick={() => handleDelete('strat-1', 'stage-2')}>删除阶段</button>;
};

方案三:组件内直接验证结果(简单场景适用)

组件在dispatch后,通过useSelector监听state变化,验证目标stage是否存在,以此判断操作是否成功。注意React状态更新是异步的,需要用useEffect触发校验。

组件代码

import { useDispatch, useSelector } from 'react-redux';
import { deleteStage } from './strategySlice';
import { useEffect, useState } from 'react';

const YourComponent = ({ strategyId, stageId }) => {
  const dispatch = useDispatch();
  const strategies = useSelector(state => state.strategy.strategies);
  const [deleteTriggered, setDeleteTriggered] = useState(false);

  const handleDelete = () => {
    dispatch(deleteStage({ strategyId, stageId }));
    setDeleteTriggered(true);
  };

  useEffect(() => {
    if (deleteTriggered) {
      const targetStrategy = strategies.find(s => s.id === strategyId);
      const stageStillExists = targetStrategy?.stages.some(s => s.id === stageId);
      
      if (!stageStillExists) {
        console.log('删除成功');
      } else {
        console.log('删除失败');
      }
      setDeleteTriggered(false);
    }
  }, [deleteTriggered, strategies, strategyId, stageId]);

  return <button onClick={handleDelete}>删除阶段</button>;
};
方案推荐

优先选择方案一,它符合Redux Toolkit的最佳实践,将状态更新逻辑集中在reducer中,组件只需处理业务反馈,代码结构清晰,还能避免状态残留问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 06:55:55