React Redux实现与React Hooks->如何在类型检查中使用useDispatch?

时间:2019-11-28 15:55:26

标签: reactjs typescript redux react-redux

我对Typescript React App中Redux的类型保存实现有一些疑问。

我已经在Reducer上完成了设置和类型检查,还使用了react-redux中的useTypedSelector。在这里,我在案例的Reducer语句中只有一件事是松散的类型检查,但这并不是那么成问题。

我的Redux商店设置:

// --------------------------------------- REDUX STORE ---------------------------------------
interface ITimePreset {
  session: number;
  break: number;
}

const UPDATE_TIMEPRESET = 'UPDATE_TIMEPRESET';
const INCREMENT_TIMEPRESET = 'INCREMENT_TIMEPRESET';
const DECREMENT_TIMEPRESET = 'DECREMENT_TIMEPRESET';
const BREAK = 'break';
const SESSION = 'session';

type Item = typeof BREAK | typeof SESSION;

interface IUpdateTimepresetAction {
  type: typeof UPDATE_TIMEPRESET;
  payload: {
    value: number;
    item: Item;
  };
}

interface IIncrementTimepresetAction {
  type: typeof INCREMENT_TIMEPRESET;
  payload: Item;
}

interface IDecrementTimepresetAction {
  type: typeof DECREMENT_TIMEPRESET;
  payload: Item;
}

type TimePresetActionTypes = IUpdateTimepresetAction | IIncrementTimepresetAction | IDecrementTimepresetAction;

const initialState: ITimePreset = {
  session: 25,
  break: 5,
};

const timePresetReducer = (state: ITimePreset = initialState, action: TimePresetActionTypes): ITimePreset => {
  switch (action.type) {
    case UPDATE_TIMEPRESET:
      return {
        ...state,
        [action.payload.item]: action.payload.value,
      };
    case INCREMENT_TIMEPRESET:
      return {
        ...state,
        [action.payload]: state[action.payload] + 1,
      };
    case DECREMENT_TIMEPRESET:
      return {
        ...state,
        [action.payload]: state[action.payload] - 1,
      };
    default:
      return state;
  }
};

const rootReducer = combineReducers({
  timePreset: timePresetReducer,
});

type RootState = ReturnType<typeof rootReducer>;

const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;

const store = createStore(rootReducer);

使用useTypedSelector进行良好的类型检查非常好:

const timePreset: ITimePreset = useTypedSelector(state => state.timePreset);

但是对于useDispatch,我没有找到用于类型检查的解决方案:

const dispatch = useDispatch();

// This is the correct one:
dispatch({ type: DECREMENT_TIMEPRESET, payload: element });

// Wrong one with no error
dispatch({ type: 'Whaaat', payload: 9 });

有没有一种方法可以对useDispatch参数进行类型检查? 您是否对实施Redux Store有其他建议(一些最佳实践)->这是我的第一个示例。

1 个答案:

答案 0 :(得分:1)

一些对您有所帮助的事情。

  1. 系统中所有动作类型的全局 ActionType 类型。
type ActionType = 'UPDATE_TIMEPRESET' | 'INCREMENT_TIMEPRESET' | 'DECREMENT_TIMEPRESET';

当然,模块的特定类型可能很重要,您不需要将它们放在一个地方,例如

import SomethingActionType from 'someModule';
import Something2ActionType from 'someModule2';
type ActionType = SomethingActionType | Something2ActionType;

  1. 定义操作类型

我们需要对Action的外观有一个一般的定义。示例类型:

type Action<P> = {
  type: ActionType,
  payload: P
}

我们的Action是类型构造函数,我们现在可以定义特定类型,例如Action<string>Action<UserRequest>

  1. 定义 ActionCreator 类型

下一步是定义ActionCreator类型。 ActionCreator只是返回有效Action的简单函数。

type ActionCreator<P> = (p: P) => Action<P>; 

  1. 加入这些概念以创建一些动作创建者

const incrementTimePreset: ActionCreator<Item> = payload => ({
   type: 'INCREMENT_TIMEPRESET' // type safe as it goes from ActionType union
   payload
})

const decrementTimePreset: ActionCreator<Item> = payload => ({
   type: 'DECREMENT_TIMEPRESET' // type safe as it goes from ActionType union
   payload
})

  1. 与useDispatch一起使用

现在,我们将使用动作创建器,而不是手动使用useDispatch和一些对象常量。

dispatch(decrementTimePreset(item))

  1. 仅对我们的操作进行自定义挂钩,可选地,因为前面的步骤足够好
const useSafeDispatch = () => {
  const dispatch = useDispatch();
  return <P>(action: Action<P>) => dispatch(action);
}

// using
const dispatch = useSafeDispatch();
dispatch(decrementTimePreset(item)); // only proper action structure is allowed