【问题标题】:React Redux implementation with React Hooks -> How to use useDispatch with type-checking?使用 React Hooks 实现 React Redux -> 如何使用 useDispatch 进行类型检查?
【发布时间】:2019-11-28 15:55:26
【问题描述】:

我对 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 的实现有其他建议吗(一些最佳实践)-> 这是我的第一个示例。

【问题讨论】:

    标签: reactjs typescript redux react-redux


    【解决方案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&lt;string&gt;Action&lt;UserRequest&gt;

    1. 定义ActionCreator类型

    下一步是定义 ActionCreator 类型。 ActionCreator 只是一个简单的函数,它返回一个有效的动作。

    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
    

    【讨论】:

    • 非常感谢这本分步指南...在第 5 步中所有的工作都像我预期的那样工作:-) ...但我不明白第 6 步我认为缺少一些东西。 .. 也许你可以检查并解释一下它是如何工作的?
    • 请再次删除一个错字检查
    • 发现问题... useSafeDispatch 的实现在 .tsx 文件中不起作用 -> 泛型被解释为 JSX 标签时出现编译器错误... 时间过长.....
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-02
    • 2019-09-11
    • 2020-03-20
    • 1970-01-01
    • 2020-01-26
    • 2021-11-12
    • 1970-01-01
    相关资源
    最近更新 更多