如何使用useDispatch强制执行类型检查?

时间:2019-08-16 20:29:19

标签: reactjs redux react-redux react-hooks

我对使用useDispatch的好处和最佳实践感到困惑。

当前,我通过导出bindActionCreators的结果来抽象访问我的商店(见下文),该结果允许使用类似组件这样的语句进行受控访问

import {counterActions} from "./store"
//...
counterActions.reset()

具有对参数和结果的完整类型检查,以及对单个操作的代码完成。

但是如果我改用useDispatch

import { useDispatch } from "react-redux"
const dispatch = useDispatch()
// ...
dispatch({type: "RESET"})

我在调用dispatch时没有进行类型或参数检查,并且可以轻松输入废话,例如

dispatch({junk: "GARBAGE", morejunk: "MOREGARBAGE"})

除非我在组件中使用类似的注释

import { CounterAction } from "../store"
// ...
const dispatch: (action: CounterAction) => void = useDispatch()

或在我的商店中创建类似

的包装
export function useMyDispatch(): (action: CounterAction) => void {
    return useDispatch()
}

然后在我的组件中使用它。

为什么useDispatch比我的counterActions好?是否有误用或遗漏的useDispatch用法成语?


store.ts

import { createStore } from "redux"
import { bindActionCreators } from 'redux'


interface CounterState {
    count: number;
}

type CounterAction =
    | { type: 'INCREMENT'; step: number }
    | { type: 'RESET' }

const initialState: CounterState = {count: 0}

const counterReducer = (state = initialState, action: CounterAction): CounterState => {
    switch (action.type) {
        case 'INCREMENT':
            return {...state, count: state.count + action.step}
        case "RESET":
            return {...state, count: 1}
        default:
            return state
    }
}

// Use only for Provider
export const store = createStore(counterReducer)

const increment = (step: number = 1): CounterAction  => ({ type: "INCREMENT", step: step })
const reset = (): CounterAction => ({ type: "RESET" })

export const counterActions = bindActionCreators(
    { increment, reset },
    store.dispatch
)

1 个答案:

答案 0 :(得分:2)

您可以创建类型化的自定义挂钩:

type Dispatch = <TReturnType>(action: Actions) => TReturnType;
const useTypedDispatch = () => useDispatch<Dispatch>();

其中Actions是您所有可用操作的并集,例如问题中的CounterAction。您可以将其用作:

const dispatch = useTypedDispatch()